Skip to content

docs(great-docs): add a Great Docs site for sdv-py — executable guides + auto-introspected reference - #112

Open
saiemgilani wants to merge 9 commits into
mainfrom
proto/quarto-docs
Open

docs(great-docs): add a Great Docs site for sdv-py — executable guides + auto-introspected reference#112
saiemgilani wants to merge 9 commits into
mainfrom
proto/quarto-docs

Conversation

@saiemgilani

@saiemgilani saiemgilani commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Adds a real Great Docs documentation site for sportsdataverse — a Quarto-based static site with an auto-introspected API reference and executable user-guide cells (real DataFrames frozen at build time). This is additive and evaluative: it does NOT replace the existing Docusaurus codegen docs; it stands up Great Docs as an option and documents the trade-offs.

Did Great Docs auto-discovery actually work? — Yes

great-docs build → 19/19 steps, ~95s, 85 HTML pages / 95 documented symbols (reproducible from clean).

The real blocker (and why a first pass looked "non-viable"): import sportsdataverse registers ~2,940 names via make_league_module(), and Great Docs' discovery validates every name with a ~2s griffe get_object() call → ~90-min walk → timeout. Discovery itself is fine; the O(n)×2s validation loop is the cost.

The fix: pin an explicit curated reference: allow-list in great-docs.yml. That takes the lightweight _categorize_referenced_objects path and skips the validation loop, plus source.enabled: false to drop the one other unscoped griffe walk. No blanket exclude needed — scoping is the allow-list.

What's here

  • great-docs.ymlmodule: sportsdataverse, dynamic: true, parser: google, source.enabled: false; theme navbar_style: slate + content_style: sky + dark_mode_toggle + hero/tagline + GitHub widget; a curated reference: of 10 sections (8 sports × ESPN entry points + NFL loaders + PBP/config classes) = 95 symbols.
  • user_guide/00-getting-started.qmd, 01-scoreboards-and-schedules.qmd — executable cells with real build-time output (espn_nba_teams() → 30×14, a scoreboard table, schedule 500×70, computed prose).
  • great-docs-preview/ — committed rendered-preview.html (opens with no build) + 3 screenshots (home / reference / user-guide) so the result is visible without building.
  • GREAT-DOCS-NOTES.md — the honest write-up + the two Windows workarounds (PYTHONUTF8=1; a jupyter: python3 frontmatter pin).
  • .gitignore — the ephemeral great-docs/ build dir.
  • The bare-Quarto site under docs-quarto/ is kept as the comparison point.

Verdict (Great Docs vs the Docusaurus codegen)

Complementary. Great Docs wins on the curated public surface + executable guides (live DataFrames beat drift-prone schema tables; batteries-included theme/search/llms.txt). The Docusaurus codegen wins on full ~800-wrapper breadth + per-column returns tables (both YAML-driven). Python could run both.

Preview

PYTHONUTF8=1 great-docs build      # → great-docs/_site/
great-docs preview                  # serves on :3000

Or open great-docs-preview/rendered-preview.html.

CI

Green (CodeRabbit, Vercel, codegen --check + tests, pytest on macOS/Ubuntu/Windows × py3.9/3.13).

Summary by CodeRabbit

Release Notes

  • Documentation
    • Added a Quarto-based documentation site with executable guides that render using live ESPN data at build time.
    • Added guides for installation, teams & scoreboards, schedules & rosters, and parsed-dataframe behavior.
    • Added MLB and NBA reference pages with signatures, parameter/return details, and real rendered examples.
    • Added an architecture overview and updated getting-started documentation.
  • Chores
    • Wired the Great Docs site into the repo toolchain via new configuration, CI automation, and documentation build artifacts caching.
    • Updated contributor and changelog pages to describe the Great Docs workflow.

Add a self-contained Quarto proof-of-concept under docs-quarto/ to compare
against the Docusaurus docs the SportsDataverse uses. The PoC demonstrates
Quarto's build-time executable Python cells: every cell runs real
sportsdataverse code at render time and freezes the output (tidy polars /
pandas DataFrames as HTML tables) into the static page.

- _quarto.yml: minimal website project, jupyter: python3, execute freeze: auto
- index.qmd: 7 executable cells (espn_nba_teams / espn_nfl_teams, polars +
  pandas round-trip) + inline computed expressions; renders clean (30 NBA /
  32 NFL teams, real team names in the HTML)
- README.md: honest Quarto-vs-Docusaurus write-up for these packages, with a
  recommendation (Quarto for the Python/R data packages; Docusaurus stays for
  the JS package) + a build-time "real output" injector hybrid
- _freeze/ committed (cached executed output); rendered-preview.html +
  quarto-poc-render.png committed so the render is visible without a build
- _site/ and .quarto/ gitignored (build artifacts)
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sportsdataverse-py Ready Ready Preview, Comment Jun 18, 2026 7:38am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@saiemgilani, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 7 minutes and 25 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a7abb0c-5ea4-4e1f-bfb1-8aff751b3e46

📥 Commits

Reviewing files that changed from the base of the PR and between 462d73c and c56a4d7.

⛔ Files ignored due to path filters (1)
  • assets/favicon.ico is excluded by !**/*.ico
📒 Files selected for processing (23)
  • CLAUDE.md
  • GREAT-DOCS-NOTES.md
  • great-docs.yml
  • tools/codegen/generate.py
  • tools/codegen/great_docs_reference.py
  • tools/convert_tutorials_to_qmd.py
  • user_guide/02-quickstart.qmd
  • user_guide/03-cfb-intro.qmd
  • user_guide/04-nfl-intro.qmd
  • user_guide/05-nba-intro.qmd
  • user_guide/06-wbb-intro.qmd
  • user_guide/07-mbb-intro.qmd
  • user_guide/08-nhl-intro.qmd
  • user_guide/09-wnba-intro.qmd
  • user_guide/10-mlb-intro.qmd
  • user_guide/11-pwhl-intro.qmd
  • user_guide/12-junior-hockey-intro.qmd
  • user_guide/13-odds-intro.qmd
  • user_guide/14-soccer-intro.qmd
  • user_guide/15-cricket-intro.qmd
  • user_guide/16-other-espn-leagues-intro.qmd
  • user_guide/getting-started.qmd
  • user_guide/scoreboards-and-schedules.qmd
📝 Walkthrough

Walkthrough

Adds a complete Quarto documentation site under docs-quarto/ with project configuration, a reference stub codegen script, hand-written executable guide and reference pages, and committed frozen execution artifacts. Also adds a Great Docs configuration (great-docs.yml) and user-guide pages (user_guide/), plus branding assets, CI automation, and comprehensive meta-documentation comparing both documentation approaches.

Changes

Quarto + Great Docs documentation site for sportsdataverse-py

Layer / File(s) Summary
Project scaffolding and site configuration
.gitignore, docs-quarto/.gitignore, docs-quarto/_quarto.yml, great-docs.yml
Adds .gitignore rules for great-docs/ and /quarto/ build artifacts; a docs-quarto/-scoped .gitignore noting _freeze/ is committed; _quarto.yml defining site output directory, multi-level navbar (guides, reference hand-written and generated, architecture), sidebar sections, HTML light/dark themes, TOC behavior, and freeze: auto execution defaults; and great-docs.yml with module settings, curated per-sport API reference sections (NBA, WNBA, NFL, College Football, Men's/Women's College Basketball, MLB, NHL), NFL data loaders subsection, and play-by-play processing class entries.
Reference stub codegen script
docs-quarto/_gen_reference.py
Adds a standalone Python script that reads endpoint YAML metadata, resolves live MLB callables from sportsdataverse.mlb, and generates deterministic Quarto .qmd reference stubs per endpoint (signature code block with fallback, docstring-based summary, markdown parameter table from YAML, returns note from schema metadata, and optional executable example cell with hardcoded reproducible arguments); writes all stubs to reference/generated/ and generates index.qmd listing all endpoints.
Quarto site pages: index, guides, reference, architecture
docs-quarto/index.qmd, docs-quarto/guides/, docs-quarto/reference/, docs-quarto/architecture.qmd
Adds the site homepage (install options, package import, real loader examples with Polars output, inline computed expressions for team counts, navigation cards); guide pages (index explaining build-time execution, installation with pip/uv/conda, teams-and-scoreboard with uniform ESPN endpoint examples, schedule-and-rosters with team_id discovery, parsed-dataframes explaining return_parsed and return_as_pandas); reference landing page explaining hand-written vs. generator-emitted approaches; hand-written executable MLB and NBA reference pages documenting function signatures, parameter/return tables, and live example cell outputs; and architecture page covering cross-league ESPN wrapper design, parser layer contract, codegen pipeline, and ecosystem multi-language overview.
Great Docs user-guide pages
user_guide/00-getting-started.qmd, user_guide/01-scoreboards-and-schedules.qmd
Adds two executable Quarto pages targeting the Great Docs build: getting-started (install commands, first ESPN API call against live endpoint, cross-sport consistency demo) and scoreboards-and-schedules (date-specific scoreboard and full-season schedule patterns, pandas output option), both executed at build time against live ESPN endpoints with frozen outputs.
Committed Quarto freeze artifacts
docs-quarto/_freeze/*/execute-results/html.json
Adds frozen execution-result JSON files for all guide and reference pages (index, installation, teams-and-scoreboard, schedule-and-rosters, parsed-dataframes, architecture, MLB reference, NBA reference), each storing a content hash, Jupyter engine metadata, embedded rendered markdown with executed cell outputs and dataframe displays, and header script includes (RequireJS and jQuery with SRI).
Branding and styling assets
assets/head.html
Adds a <head> template injecting Plausible analytics script (set to py.sportsdataverse.org), external font loads from Google Fonts and FiraCode CDN, and inline CSS defining the cyan-glow animation keyframes and typography styling retargeted to Quarto/Bootstrap structures (navbar brand/title, heading levels, sidebar/nav links, code blocks) plus emphasis styling for strong.sdv-brand and b.sdv-brand.
CI/CD workflow integration
.github/workflows/great-docs.yml
Adds a GitHub Actions workflow triggered by changes to great-docs.yml, user_guide/**, or assets/** (and via manual dispatch), that installs Python 3.13.2 and Quarto, syncs project dependencies with docs/all extras, runs a non-blocking Great Docs build (continuing on error due to live API usage), and uploads the rendered great-docs/_site artifact.
Meta-documentation and project metadata updates
docs-quarto/README.md, GREAT-DOCS-NOTES.md, CHANGELOG.md, CLAUDE.md, CONTRIBUTING.md, README.md, docs/src/pages/CHANGELOG.md, pyproject.toml
Adds docs-quarto/README.md covering the Quarto site structure, local render instructions, a detailed Great Docs vs. Docusaurus comparison (including failure modes and evaluation across dimensions), migration-effort estimate, per-package recommendations (Python use Quarto fallback, R fit Quarto, JS keep Docusaurus), and a hybrid injection proposal. Adds GREAT-DOCS-NOTES.md documenting the successful second Great Docs build, the curated reference: configuration fix for auto-discovery timeouts, working build outcomes (pages, reference sections, executable guides hitting ESPN at build time), and a comparison table with Docusaurus codegen. Updates project documentation files (CHANGELOG, CLAUDE, CONTRIBUTING, README, docs/src/pages/CHANGELOG) with sections describing the Great Docs integration, local build/preview commands, Windows-specific notes, and the non-blocking CI behavior. Adds docs optional-dependency group to pyproject.toml with great-docs>=0.14.0; python_version >= '3.11' and includes it in the all group.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Suggested reviewers

  • akeaswaran

Poem

🐇 A rabbit hops through frozen frames,
Where ESPN tables wear their names.
Quarto renders, cells are locked in ice,
Great Docs configured—oh, how nice!
With YAML curated, no timeouts remain,
The docs site blooms like spring after rain. 🌸

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a Great Docs site with executable guides and auto-introspected API reference documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch proto/quarto-docs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Extend the single-page PoC into a complete, navigable Quarto website that
mirrors the production Docusaurus structure (Home / Guides / Reference /
Architecture) with navbar + sidebar + overlay search.

- Home (index.qmd): install tabs + executable surface tour with real frames.
- Guides (guides/*.qmd): installation, teams & scoreboard, schedule & rosters,
  and the parser layer — all build-time-executed against live ESPN endpoints,
  with output frozen via execute: freeze: auto.
- Reference: hand-written executable reference for MLB (4 fns) and NBA (3 fns)
  with real df output, plus _gen_reference.py emitting 21 MLB .qmd stubs from
  the endpoint YAML + live signatures (proves the codegen -> .qmd path).
- Architecture (architecture.qmd): ESPN cross-league core, parser layer, and
  the codegen pipeline, with a build-time table computed from the real YAML.
- quarto render -> 32 pages, no execution errors; real output verified in HTML.

Tried Great Docs first (pip install great-docs): it installs but its package
auto-discovery is non-viable against this package's dynamically-generated,
submodule-namespaced 800-wrapper surface (init/scan/build time out or fail to
resolve the dynamic names). Fell back to a clean Quarto website per the brief
and documented the deviation. README.md rewritten as a full-conversion
evaluation (effort estimate + per-package recommendation + executable vs
schema-table reference comparison). Adds 3 screenshots + a self-contained
rendered-preview.html so the result is viewable without building.
@saiemgilani saiemgilani changed the title proto: Quarto (.qmd) docs PoC with executable cells (vs Docusaurus) proto: full Quarto + Great-Docs docs conversion under docs-quarto (vs Docusaurus) Jun 18, 2026
…scovery works)

Build an actual Great Docs (Posit, v0.14.0) documentation site for the
package, succeeding where the first pass fell back to plain Quarto. The
blocker was never that the dynamic 800-wrapper surface "defeats"
discovery — it was that Great Docs' auto-discovery validates every one of
the ~2,769 import-time names through griffe's dynamic loader (~2s each =
~90 min), so init/build time out.

The fix is the documented escape hatch: pin an explicit, curated
`reference:` in great-docs.yml. `_create_api_sections_with_config()`
prioritizes it over auto-discovery and skips the per-symbol validation
loop, so the build runs in ~100s. Pair with `source.enabled: false` to
drop the other unscoped griffe walk.

What's committed:
- great-docs.yml — module: sportsdataverse, dynamic: true, parser: google,
  curated reference (8 sports x 8 ESPN entry points + NFL loaders + PBP/
  config classes = 95 documented symbols), slate navbar + sky content glow
  + dark-mode toggle + hero + GitHub widget.
- user_guide/00-getting-started.qmd, 01-scoreboards-and-schedules.qmd —
  executable cells that run against the live ESPN API at build time and
  freeze real DataFrame output (espn_nba_teams() -> 30x14, a scoreboard
  with MIN @ BOS / Final/OT, schedule 500x70, build-time-computed prose).
- assets/logo.png — hero logo + auto-generated favicon.
- great-docs-preview/ — self-contained rendered-preview.html (opens with
  no build) + 3 screenshots (themed home, reference page, user guide).
- GREAT-DOCS-NOTES.md — honest evaluation: what made auto-discovery work,
  the scope needed, and Great-Docs-autodoc vs the Docusaurus codegen
  reference; supersedes the "non-viable" conclusion in docs-quarto/README.md.

Build: 19/19 steps, ~100s, great-docs/_site/index.html + 85 HTML pages.
The ephemeral great-docs/ build dir is gitignored.
@saiemgilani saiemgilani changed the title proto: full Quarto + Great-Docs docs conversion under docs-quarto (vs Docusaurus) docs(great-docs): add a Great Docs site for sdv-py — executable guides + auto-introspected reference Jun 18, 2026
@saiemgilani
saiemgilani marked this pull request as ready for review June 18, 2026 06:18
Copilot AI review requested due to automatic review settings June 18, 2026 06:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an additive Great Docs (Quarto) documentation site for sportsdataverse-py, including a curated auto-introspected API reference and executable user-guide pages, while preserving the existing Docusaurus/codegen docs and retaining the prior docs-quarto/ evaluation site.

Changes:

  • Introduces great-docs.yml with an explicit curated reference: allow-list to avoid Great Docs’ expensive dynamic auto-discovery over the package’s large dynamically-registered surface.
  • Adds executable Great Docs user guide pages under user_guide/ demonstrating live ESPN API calls rendered at build time.
  • Updates/extends the existing docs-quarto/ evaluation site (including a small generator and committed _freeze/ execution outputs).

Reviewed changes

Copilot reviewed 26 out of 63 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.gitignore Ignores Great Docs build artifacts and root-level Quarto cache dirs.
GREAT-DOCS-NOTES.md Documents the working Great Docs approach and the curated-reference workaround.
great-docs.yml Great Docs config: theming, source/changelog disablement, and curated reference: allow-list.
user_guide/00-getting-started.qmd Executable Great Docs “Getting started” guide with live frames.
user_guide/01-scoreboards-and-schedules.qmd Executable Great Docs guide for scoreboards/schedules + pandas example.
docs-quarto/.gitignore Quarto project ignores; notes _freeze/ is committed.
docs-quarto/_quarto.yml Quarto website configuration (nav/sidebar/theme/execution defaults).
docs-quarto/_gen_reference.py Generator to emit Quarto .qmd reference stubs from endpoint YAML + live signatures.
docs-quarto/README.md Extended Quarto/Great Docs evaluation write-up (now points to GREAT-DOCS-NOTES as superseding).
docs-quarto/index.qmd Quarto site home page with executable cells.
docs-quarto/architecture.qmd Architecture + codegen pipeline overview with executable YAML introspection snippet.
docs-quarto/guides/index.qmd Guides landing page for the Quarto evaluation site.
docs-quarto/guides/installation.qmd Executable install/import verification guide.
docs-quarto/guides/teams-and-scoreboard.qmd Executable teams + past-dated scoreboard guide.
docs-quarto/guides/schedule-and-rosters.qmd Executable team_id → schedule/roster walkthrough.
docs-quarto/guides/parsed-dataframes.qmd Explains return_parsed / return_as_pandas with executable examples.
docs-quarto/reference/index.qmd Reference landing page explaining handwritten vs generated stubs.
docs-quarto/reference/mlb.qmd Handwritten executable MLB reference examples.
docs-quarto/reference/nba.qmd Handwritten executable NBA reference examples.
docs-quarto/reference/generated/index.qmd Index of generator-emitted MLB stubs.
docs-quarto/reference/generated/calendar.qmd Generated stub for espn_mlb_calendar (currently inconsistent vs endpoint metadata).
docs-quarto/reference/generated/conferences.qmd Generated stub for espn_mlb_conferences.
docs-quarto/reference/generated/draft.qmd Generated stub for espn_mlb_draft.
docs-quarto/reference/generated/injuries.qmd Generated stub for espn_mlb_injuries.
docs-quarto/reference/generated/news.qmd Generated stub for espn_mlb_news.
docs-quarto/reference/generated/scoreboard.qmd Generated stub for espn_mlb_scoreboard.
docs-quarto/reference/generated/standings.qmd Generated stub for espn_mlb_standings.
docs-quarto/reference/generated/statistics_league.qmd Generated stub for espn_mlb_statistics_league.
docs-quarto/reference/generated/summary.qmd Generated stub for espn_mlb_summary.
docs-quarto/reference/generated/team.qmd Generated stub for espn_mlb_team.
docs-quarto/reference/generated/team_depthcharts.qmd Generated stub for espn_mlb_team_depthcharts.
docs-quarto/reference/generated/team_history.qmd Generated stub for espn_mlb_team_history.
docs-quarto/reference/generated/team_injuries.qmd Generated stub for espn_mlb_team_injuries.
docs-quarto/reference/generated/team_leaders.qmd Generated stub for espn_mlb_team_leaders.
docs-quarto/reference/generated/team_news.qmd Generated stub for espn_mlb_team_news.
docs-quarto/reference/generated/team_record.qmd Generated stub for espn_mlb_team_record.
docs-quarto/reference/generated/team_roster.qmd Generated stub for espn_mlb_team_roster.
docs-quarto/reference/generated/team_schedule.qmd Generated stub for espn_mlb_team_schedule.
docs-quarto/reference/generated/team_transactions.qmd Generated stub for espn_mlb_team_transactions.
docs-quarto/reference/generated/teams_site.qmd Generated stub for espn_mlb_teams_site.
docs-quarto/reference/generated/transactions.qmd Generated stub for espn_mlb_transactions.
docs-quarto/_freeze/site_libs/clipboard/clipboard.min.js Generated/vendor JS captured under _freeze/.
docs-quarto/_freeze/index/execute-results/html.json Frozen execution output for Quarto index.
docs-quarto/_freeze/architecture/execute-results/html.json Frozen execution output for architecture page.
docs-quarto/_freeze/guides/installation/execute-results/html.json Frozen execution output for install guide.
docs-quarto/_freeze/guides/teams-and-scoreboard/execute-results/html.json Frozen execution output for teams/scoreboard guide.
docs-quarto/_freeze/guides/schedule-and-rosters/execute-results/html.json Frozen execution output for schedule/rosters guide.
docs-quarto/_freeze/guides/parsed-dataframes/execute-results/html.json Frozen execution output for parser-layer guide.
docs-quarto/_freeze/reference/mlb/execute-results/html.json Frozen execution output for handwritten MLB reference.
docs-quarto/_freeze/reference/nba/execute-results/html.json Frozen execution output for handwritten NBA reference.
docs-quarto/_freeze/reference/generated/conferences/execute-results/html.json Frozen execution output for generated conferences stub.
docs-quarto/_freeze/reference/generated/news/execute-results/html.json Frozen execution output for generated news stub.
docs-quarto/_freeze/reference/generated/scoreboard/execute-results/html.json Frozen execution output for generated scoreboard stub.
docs-quarto/_freeze/reference/generated/teams_site/execute-results/html.json Frozen execution output for generated teams_site stub.
Comments suppressed due to low confidence (1)

docs-quarto/.gitignore:14

  • docs-quarto/_freeze/site_libs/ contains generated/vendor assets (e.g. minified clipboard.js) that are not part of the executed-output cache and will churn with Quarto upgrades. If the goal is to commit only the executed results for reproducibility, it’s better to ignore _freeze/site_libs/ and keep just the execute-results/*.json artifacts under _freeze/.
# NOTE: _freeze/ IS committed on purpose — it is the cached executed output
# (the proof the cells ran against live data) and lets `quarto render` reuse
# results without re-hitting the live ESPN endpoints.



def main() -> int:
import sportsdataverse.mlb as mlb # imported here so failures are clear

```{python}
n = games.shape[0]
home_wins = games.filter(pl.col("home_winner") == True).shape[0]
Comment on lines +72 to +74
teams_pd = espn_nba_scoreboard(dates=20240110, return_as_pandas=True)
print(type(teams_pd).__module__ + "." + type(teams_pd).__name__)
print(list(teams_pd.columns[:6]))

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-quarto/_gen_reference.py`:
- Around line 62-88: The functions _summary, _param_table, and _returns_note in
the module lack complete type hints and the module is not included in mypy
validation. Import Callable and Any from typing at the top of the file, then add
full type hints: for _summary change the fn parameter from untyped to Callable,
for _param_table change ep from bare dict to a proper type (likely Any) and fn
from untyped to Callable, and for _returns_note change ep from bare dict to a
proper type (likely Any). Finally, append "docs-quarto/_gen_reference.py" to the
files list under [tool.mypy] in pyproject.toml.

In `@docs-quarto/architecture.qmd`:
- Around line 44-49: The "evaluation write-up" link in the callout block uses a
temporary PR branch reference (proto/quarto-docs) that will not exist after
merge. Update the link to use a stable reference by either replacing the branch
name with main in the GitHub URL (keeping the full path to
docs-quarto/README.md), or use a relative link to the local README.md file since
it exists in the same directory as architecture.qmd. Choose whichever approach
best fits the documentation's linking strategy.

In `@docs-quarto/reference/mlb.qmd`:
- Around line 130-158: The `espn_mlb_scoreboard` function documentation is
missing the `return_parsed` parameter that exists in the actual implementation.
Add `return_parsed: bool = True` as a parameter in the function signature (it
should be a keyword-only parameter after the asterisk and before
`return_as_pandas`). Update the return type from `pl.DataFrame` to `pl.DataFrame
| dict` to reflect that the return type depends on the `return_parsed` value.
Finally, add a new row to the parameters table documenting `return_parsed` with
type `bool`, default `True`, and a description explaining that when `True` it
returns a tidy frame and when `False` it returns raw `Dict` data.

In `@docs-quarto/reference/nba.qmd`:
- Around line 88-93: The `espn_nba_scoreboard` function documentation is missing
the `return_parsed` parameter and has an inaccurate return type annotation.
Update the function signature in the docstring to include `return_parsed: bool =
True` as a keyword-only parameter, and change the return type annotation from
`pl.DataFrame` to `pl.DataFrame | dict` to accurately reflect that it returns a
Dict when `return_parsed=False`. Add a new row to the Parameters table
documenting the `return_parsed` parameter with its default value and description
explaining it controls whether a parsed tidy frame or raw Dict is returned.
Finally, update the Returns section to clarify that it returns either a tidy
polars DataFrame or the raw ESPN Dict depending on the `return_parsed` parameter
value, and update the description text to note that this function is
parser-backed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3f646e6-5741-4ab6-abe9-712a9c175a89

📥 Commits

Reviewing files that changed from the base of the PR and between 6c56f8f and 97fcc26.

⛔ Files ignored due to path filters (34)
  • assets/logo.png is excluded by !**/*.png
  • docs-quarto/_freeze/reference/generated/conferences/execute-results/html.json is excluded by !**/generated/**
  • docs-quarto/_freeze/reference/generated/news/execute-results/html.json is excluded by !**/generated/**
  • docs-quarto/_freeze/reference/generated/scoreboard/execute-results/html.json is excluded by !**/generated/**
  • docs-quarto/_freeze/reference/generated/teams_site/execute-results/html.json is excluded by !**/generated/**
  • docs-quarto/_freeze/site_libs/clipboard/clipboard.min.js is excluded by !**/*.min.js
  • docs-quarto/quarto-generated-ref.png is excluded by !**/*.png
  • docs-quarto/quarto-guide.png is excluded by !**/*.png
  • docs-quarto/quarto-home.png is excluded by !**/*.png
  • docs-quarto/reference/generated/calendar.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/conferences.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/draft.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/index.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/injuries.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/news.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/scoreboard.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/standings.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/statistics_league.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/summary.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_depthcharts.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_history.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_injuries.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_leaders.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_news.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_record.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_roster.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_schedule.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/team_transactions.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/teams_site.qmd is excluded by !**/generated/**
  • docs-quarto/reference/generated/transactions.qmd is excluded by !**/generated/**
  • great-docs-preview/great-docs-home.png is excluded by !**/*.png
  • great-docs-preview/great-docs-reference.png is excluded by !**/*.png
  • great-docs-preview/great-docs-userguide.png is excluded by !**/*.png
📒 Files selected for processing (29)
  • .gitignore
  • GREAT-DOCS-NOTES.md
  • docs-quarto/.gitignore
  • docs-quarto/README.md
  • docs-quarto/_freeze/architecture/execute-results/html.json
  • docs-quarto/_freeze/guides/installation/execute-results/html.json
  • docs-quarto/_freeze/guides/parsed-dataframes/execute-results/html.json
  • docs-quarto/_freeze/guides/schedule-and-rosters/execute-results/html.json
  • docs-quarto/_freeze/guides/teams-and-scoreboard/execute-results/html.json
  • docs-quarto/_freeze/index/execute-results/html.json
  • docs-quarto/_freeze/reference/mlb/execute-results/html.json
  • docs-quarto/_freeze/reference/nba/execute-results/html.json
  • docs-quarto/_gen_reference.py
  • docs-quarto/_quarto.yml
  • docs-quarto/architecture.qmd
  • docs-quarto/guides/index.qmd
  • docs-quarto/guides/installation.qmd
  • docs-quarto/guides/parsed-dataframes.qmd
  • docs-quarto/guides/schedule-and-rosters.qmd
  • docs-quarto/guides/teams-and-scoreboard.qmd
  • docs-quarto/index.qmd
  • docs-quarto/reference/index.qmd
  • docs-quarto/reference/mlb.qmd
  • docs-quarto/reference/nba.qmd
  • docs-quarto/rendered-preview.html
  • great-docs-preview/rendered-preview.html
  • great-docs.yml
  • user_guide/00-getting-started.qmd
  • user_guide/01-scoreboards-and-schedules.qmd

Comment on lines +62 to +88
def _summary(fn) -> str:
doc = inspect.getdoc(fn) or ""
first = doc.strip().splitlines()[0] if doc.strip() else ""
# docstrings often start "espn_mlb_x - <summary>."; keep the human half.
if " - " in first:
first = first.split(" - ", 1)[1]
return first or "ESPN endpoint."


def _param_table(ep: dict, fn) -> str:
rows = []
for kind in ("path_params", "extra_params"):
for p in ep.get(kind, []) or []:
required = "Y" if p.get("required") else ""
default = p.get("default", "")
# escape the pipe in union types (e.g. int|str) so it doesn't break
# the markdown table column boundaries.
ptype = str(p.get("type", "")).replace("|", "\\|")
rows.append(f"| `{p['name']}` | `{ptype}` | `{default}` | {required} |")
# always-present passthrough flags
rows.append("| `return_parsed` | `bool` | `True` | |")
rows.append("| `return_as_pandas` | `bool` | `False` | |")
header = "| Parameter | Type | Default | Required |\n|---|---|---|:---:|\n"
return header + "\n".join(rows)


def _returns_note(ep: dict) -> str:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify mypy config includes/handles the new module path requirement from guidelines.
# Read-only checks only.
fd -HI '^pyproject\.toml$' -x sed -n '1,260p' {}
rg -n --no-heading '\[tool\.mypy\]|\[\[tool\.mypy\.overrides\]\]|files\s*=|module\s*=' pyproject.toml
rg -n --no-heading '_gen_reference|docs[-_]quarto' pyproject.toml

Repository: sportsdataverse/sportsdataverse-py

Length of output: 7715


🏁 Script executed:

# Read the complete [tool.mypy] section to see the files list
sed -n '260,350p' pyproject.toml

Repository: sportsdataverse/sportsdataverse-py

Length of output: 1578


🏁 Script executed:

# Check if docs-quarto/_gen_reference.py exists and read the target lines
if [ -f "docs-quarto/_gen_reference.py" ]; then
  echo "=== File exists. Reading lines 60-90 ===";
  sed -n '60,90p' docs-quarto/_gen_reference.py;
else
  echo "File not found at docs-quarto/_gen_reference.py. Searching for it...";
  find . -name "_gen_reference.py" 2>/dev/null;
fi

Repository: sportsdataverse/sportsdataverse-py

Length of output: 1329


🏁 Script executed:

# Check if this is a new file and its status
git log --oneline --all -- docs-quarto/_gen_reference.py 2>/dev/null | head -5
git status docs-quarto/_gen_reference.py 2>/dev/null

Repository: sportsdataverse/sportsdataverse-py

Length of output: 236


🏁 Script executed:

# Read top of the file to see imports and confirm structure
head -n 60 docs-quarto/_gen_reference.py

Repository: sportsdataverse/sportsdataverse-py

Length of output: 2049


Add complete type hints for helper functions and append module to mypy files list.

Lines 62, 71, and 88 use partially/untyped parameters in a module that must meet the repo's strict type-hint standard. The module is not yet included in the mypy files list in pyproject.toml.

  • Line 62: fn parameter is untyped
  • Line 71: ep uses bare dict; fn is untyped
  • Line 88: ep uses bare dict

Add imports for Callable and Any, apply full type hints, then append "docs-quarto/_gen_reference.py" to the [tool.mypy] files list in pyproject.toml.

Suggested patch
 from __future__ import annotations
 
 import inspect
 import pathlib
 import warnings
+from collections.abc import Callable
+from typing import Any

...

-def _summary(fn) -> str:
+def _summary(fn: Callable[..., Any]) -> str:
     doc = inspect.getdoc(fn) or ""

-def _param_table(ep: dict, fn) -> str:
+def _param_table(ep: dict[str, Any], fn: Callable[..., Any]) -> str:
     rows = []

-def _returns_note(ep: dict) -> str:
+def _returns_note(ep: dict[str, Any]) -> str:
     parser = ep.get("parser")

In pyproject.toml, append to the [tool.mypy] files list:

 files = [
     "sportsdataverse/_deprecation.py",
     ...
     "sportsdataverse/mlb/mlb_statcast_extra.py",
+    "docs-quarto/_gen_reference.py",
 ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-quarto/_gen_reference.py` around lines 62 - 88, The functions _summary,
_param_table, and _returns_note in the module lack complete type hints and the
module is not included in mypy validation. Import Callable and Any from typing
at the top of the file, then add full type hints: for _summary change the fn
parameter from untyped to Callable, for _param_table change ep from bare dict to
a proper type (likely Any) and fn from untyped to Callable, and for
_returns_note change ep from bare dict to a proper type (likely Any). Finally,
append "docs-quarto/_gen_reference.py" to the files list under [tool.mypy] in
pyproject.toml.

Source: Coding guidelines

Comment on lines +44 to +49
::: {.callout-important}
This dynamic, namespaced generation is exactly what makes auto-introspection
documentation tools struggle with this package — there is no static `__all__` of
flat names to discover. See the [evaluation write-up](https://github.com/sportsdataverse/sportsdataverse-py/blob/proto/quarto-docs/docs-quarto/README.md)
for how that shaped the Great-Docs result.
:::

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the architecture.qmd file
find . -name "architecture.qmd" -type f

Repository: sportsdataverse/sportsdataverse-py

Length of output: 109


🏁 Script executed:

# Check if docs-quarto directory exists and list its contents
ls -la docs-quarto/ 2>/dev/null | head -30

Repository: sportsdataverse/sportsdataverse-py

Length of output: 1072


🏁 Script executed:

# Read lines 44-49 of the architecture.qmd file
if [ -f "docs-quarto/architecture.qmd" ]; then
  sed -n '44,49p' docs-quarto/architecture.qmd
fi

Repository: sportsdataverse/sportsdataverse-py

Length of output: 462


🏁 Script executed:

# Check if README.md exists in docs-quarto
ls -la docs-quarto/README.md 2>/dev/null

Repository: sportsdataverse/sportsdataverse-py

Length of output: 150


🏁 Script executed:

# Check all branches in the repository
git branch -a 2>/dev/null | head -20

Repository: sportsdataverse/sportsdataverse-py

Length of output: 176


Update the GitHub link to use a stable branch reference.

The link on line 47 references the proto/quarto-docs branch, which is a temporary PR branch that will not exist after merge. The README.md file exists locally in the same directory, so update to either:

  1. Use the stable main branch:
https://github.com/sportsdataverse/sportsdataverse-py/blob/main/docs-quarto/README.md
  1. Or use a relative link:
[evaluation write-up](./README.md)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-quarto/architecture.qmd` around lines 44 - 49, The "evaluation write-up"
link in the callout block uses a temporary PR branch reference
(proto/quarto-docs) that will not exist after merge. Update the link to use a
stable reference by either replacing the branch name with main in the GitHub URL
(keeping the full path to docs-quarto/README.md), or use a relative link to the
local README.md file since it exists in the same directory as architecture.qmd.
Choose whichever approach best fits the documentation's linking strategy.

Comment on lines +130 to +158
## `espn_mlb_scoreboard`

```python
espn_mlb_scoreboard(dates: int | str | None = None, *, season_type: int | None = None,
return_as_pandas: bool = False, **kwargs) -> pl.DataFrame
```

The scoreboard for a given date (`YYYYMMDD`).

**Parameters**

| Parameter | Type | Default | Description |
|---|---|---|---|
| `dates` | `int \| str` | `None` | Date in `YYYYMMDD`; defaults to today. |
| `season_type` | `int` | `None` | ESPN season type (2 = regular, 3 = postseason). |
| `return_as_pandas` | `bool` | `False` | If `True`, return a pandas DataFrame. |

**Returns** — a tidy `polars.DataFrame`, one row per game on the slate.

**Example**

```{python}
from sportsdataverse.mlb import espn_mlb_scoreboard

sb = espn_mlb_scoreboard(dates="20240615")
print("shape:", sb.shape)
keep = [c for c in ["id", "name", "short_name", "status_type_detail"] if c in sb.columns]
sb.select(keep).head(6)
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document the return_parsed parameter for espn_mlb_scoreboard.

The signature and parameters table for espn_mlb_scoreboard (lines 130–158) omit the return_parsed parameter. According to the context from sportsdataverse/mlb/mlb_espn_ext.py:150–198, the actual function signature includes return_parsed: bool = True, which controls whether to return a tidy DataFrame or raw JSON Dict. The documented return type should reflect this: pl.DataFrame | dict (depending on return_parsed), not just pl.DataFrame.

This is inconsistent with the documentation for the other three functions (espn_mlb_teams, espn_mlb_team_schedule, espn_mlb_team_roster), which correctly document return_parsed.

🔧 Suggested fix

Update the signature block and parameters table:

 ## `espn_mlb_scoreboard`

 ```python
-espn_mlb_scoreboard(dates: int | str | None = None, *, season_type: int | None = None,
-                    return_as_pandas: bool = False, **kwargs) -> pl.DataFrame
+espn_mlb_scoreboard(dates: int | str | None = None, *, season_type: int | None = None,
+                    return_parsed: bool = True,
+                    return_as_pandas: bool = False, **kwargs) -> pl.DataFrame | dict

Parameters

Parameter Type Default Description
dates int | str None Date in YYYYMMDD; defaults to today.
season_type int None ESPN season type (2 = regular, 3 = postseason).
+ return_parsed bool True
return_as_pandas bool False If True, return a pandas DataFrame.
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs-quarto/reference/mlb.qmd around lines 130 - 158, The
espn_mlb_scoreboard function documentation is missing the return_parsed
parameter that exists in the actual implementation. Add return_parsed: bool = True as a parameter in the function signature (it should be a keyword-only
parameter after the asterisk and before return_as_pandas). Update the return
type from pl.DataFrame to pl.DataFrame | dict to reflect that the return
type depends on the return_parsed value. Finally, add a new row to the
parameters table documenting return_parsed with type bool, default True,
and a description explaining that when True it returns a tidy frame and when
False it returns raw Dict data.


</details>

<!-- fingerprinting:phantom:triton:mongoose -->

<!-- cr-comment:v1:556eeceab77c18fbdcebf51b -->

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +88 to +93
## `espn_nba_scoreboard`

```python
espn_nba_scoreboard(dates: int | str | None = None, *,
return_as_pandas: bool = False, **kwargs) -> pl.DataFrame
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Incomplete function signature: return_parsed parameter missing and return type inaccurate.

The documented signature omits the return_parsed: bool = True parameter. When return_parsed=False, the function returns the raw Dict, not a pl.DataFrame. This is a breaking contract difference that should be surfaced in the documentation.

The full signature from the upstream function (Context snippet 3) is:

espn_nba_scoreboard(
    dates: int | str | None = None,
    week: int | None = None,
    season_type: int | None = None,
    groups: int | str | None = None,
    limit: int = 500,
    *,
    return_parsed: bool = True,  # <-- MISSING in docs
    return_as_pandas: bool = False,
    **kwargs,
) -> pl.DataFrame | dict
📝 Suggested fix for scoreboard signature and returns block
 ## `espn_nba_scoreboard`
 
 ```python
-espn_nba_scoreboard(dates: int | str | None = None, *,
-                    return_as_pandas: bool = False, **kwargs) -> pl.DataFrame
+espn_nba_scoreboard(dates: int | str | None = None, *,
+                    return_parsed: bool = True,
+                    return_as_pandas: bool = False, **kwargs) -> pl.DataFrame | dict

-The scoreboard for a given date (YYYYMMDD).
+The scoreboard for a given date (YYYYMMDD). Parser-backed, so return_parsed=True is the default.

Parameters

Parameter Type Default Description
dates int | str None Date in YYYYMMDD; defaults to today.
+ return_parsed bool True
return_as_pandas bool False If True, return a pandas DataFrame.

-Returns — a tidy polars.DataFrame, one row per game on the slate.
+Returns — a tidy polars.DataFrame, one row per game on the slate; or the raw ESPN Dict when return_parsed=False.


</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs-quarto/reference/nba.qmd around lines 88 - 93, The
espn_nba_scoreboard function documentation is missing the return_parsed
parameter and has an inaccurate return type annotation. Update the function
signature in the docstring to include return_parsed: bool = True as a
keyword-only parameter, and change the return type annotation from
pl.DataFrame to pl.DataFrame | dict to accurately reflect that it returns a
Dict when return_parsed=False. Add a new row to the Parameters table
documenting the return_parsed parameter with its default value and description
explaining it controls whether a parsed tidy frame or raw Dict is returned.
Finally, update the Returns section to clarify that it returns either a tidy
polars DataFrame or the raw ESPN Dict depending on the return_parsed parameter
value, and update the description text to note that this function is
parser-backed.


</details>

<!-- fingerprinting:phantom:triton:mongoose -->

<!-- cr-comment:v1:a7084229291acd3fcb70fbf9 -->

<!-- This is an auto-generated comment by CodeRabbit -->

…, informational CI)

Make the additive Great Docs site (great-docs.yml + user_guide/*.qmd) a
first-class, reproducible part of the repo without touching the runtime
package or the production Docusaurus codegen docs.

- pyproject: add a `docs` optional-dependencies extra carrying great-docs
  (flows into `all`); marker-gated to python_version >= 3.11 so the package's
  requires-python = ">=3.9" runtime support is unchanged. Quarto noted as a
  separate SYSTEM install. Re-locked uv.lock.
- CLAUDE.md: new "Great Docs site" subsection under the docs toolchain area —
  complementary-not-replacement framing, the curated reference allow-list
  rationale (~2,940 dynamic wrappers -> ~90-min walk; allow-list -> ~95s build),
  build/preview commands + Windows PYTHONUTF8/jupyter pins, gitignore + live-API
  notes. Doctoc TOC regenerated.
- CONTRIBUTING.md: short Great Docs subsection (install via docs extra + Quarto,
  build/preview, gitignore + curated-reference notes).
- README.md: brief mention of the alternative executable-guides site.
- CHANGELOG.md: Unreleased Docs entry.
- CI: .github/workflows/great-docs.yml builds the site + uploads _site as an
  artifact on changes to great-docs.yml / user_guide/** / assets/**. Informational
  and non-blocking (continue-on-error on the live-cell build step; job named
  "(informational)") so a flaky live ESPN render never blocks a merge. No
  deployment wired in.
…clude_in_header

Port the Docusaurus brand surface into the Great Docs site head:
- Plausible analytics (same src + data-domain as docs/docusaurus.config.ts)
- Bungee / Chivo / Lato / Fira Mono + FiraCode CDN font stack (custom.css URLs)
- the cyan glow @Keyframes, retargeted to Quarto/Bootstrap selectors

Injected via include_in_header: [{file: assets/head.html}] in great-docs.yml.
Verified in the built _site/index.html <head>: plausible.io, Bungee, and the
text-shadow glow CSS all present.
Copy the Docusaurus favicon (docs/static/img/favicon.ico -> assets/favicon.ico,
15086 bytes byte-identical) and pin it via favicon: in great-docs.yml so the
browser-tab icon matches. Document why we keep navbar_style: slate (the dark
brand gradient the cyan glow sits on) rather than a solid navbar_color, and
that the single brand logo serves both light/dark (no dark variant on the
Docusaurus site either). Built _site/index.html links ./favicon.ico and renders
the logo.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
assets/head.html (1)

21-25: ⚡ Quick win

Remove the duplicate Fira Code source and keep one maintained provider.

Line 21 and Line 25 both load Fira Code from different CDNs. This adds an unnecessary request and introduces avoidable fragility (the RawGit CDN is legacy). Keep only one source (prefer the Google Fonts entry already present at Line 25).

Suggested diff
-<link rel="stylesheet" href="https://cdn.rawgit.com/tonsky/FiraCode/1.205/distr/fira_code.css">
 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Chivo&display=swap">
 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lato&display=swap">
 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fira+Mono&display=swap">
 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fira+Code&display=swap">
 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bungee&display=swap">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/head.html` around lines 21 - 25, The head.html file contains duplicate
Fira Code font declarations loading from two different CDNs. Remove the RawGit
CDN link for Fira Code
(https://cdn.rawgit.com/tonsky/FiraCode/1.205/distr/fira_code.css) and keep only
the Google Fonts entry
(https://fonts.googleapis.com/css2?family=Fira+Code&display=swap) which is a
maintained provider. This eliminates unnecessary requests and removes the
fragility of relying on the legacy RawGit CDN.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/great-docs.yml:
- Around line 39-67: Replace all mutable action version tags with full
40-character commit SHAs to prevent supply-chain attacks: update
actions/checkout@v5 to use its pinned SHA, astral-sh/setup-uv@v8.1.0 to use its
pinned SHA, quarto-dev/quarto-actions/setup@v2 to use its pinned SHA, and
actions/upload-artifact@v4 to use its pinned SHA. Additionally, add
persist-credentials: false to the actions/checkout step configuration since no
authenticated Git operations are performed in this workflow and the GITHUB_TOKEN
does not need to be available to subsequent steps.

In `@pyproject.toml`:
- Around line 104-114: The pyjanitor dependency declarations in pyproject.toml
currently have only a lower bound constraint (>=0.23.1) without an upper bound,
which could cause compatibility issues since pyjanitor 0.32.18+ requires pandas
3.x. Locate all three pyjanitor entries in the dependencies section of
pyproject.toml (referenced at lines 68, 96, and 134) and update each instance by
adding the upper bound constraint to read pyjanitor>=0.23.1,<0.32.18 instead of
just the lower bound.

---

Nitpick comments:
In `@assets/head.html`:
- Around line 21-25: The head.html file contains duplicate Fira Code font
declarations loading from two different CDNs. Remove the RawGit CDN link for
Fira Code (https://cdn.rawgit.com/tonsky/FiraCode/1.205/distr/fira_code.css) and
keep only the Google Fonts entry
(https://fonts.googleapis.com/css2?family=Fira+Code&display=swap) which is a
maintained provider. This eliminates unnecessary requests and removes the
fragility of relying on the legacy RawGit CDN.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e1dbbf5-0c19-4369-88d9-9814dd5f1309

📥 Commits

Reviewing files that changed from the base of the PR and between 97fcc26 and 462d73c.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/great-docs.yml
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • README.md
  • assets/head.html
  • docs/src/pages/CHANGELOG.md
  • great-docs.yml
  • pyproject.toml
✅ Files skipped from review due to trivial changes (3)
  • README.md
  • CHANGELOG.md
  • docs/src/pages/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • great-docs.yml

Comment on lines +39 to +67
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
with:
version: "latest"
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Set up Python
run: uv python install 3.13.2
- name: Install Linux build deps for pyreadr sdist fallback
run: |
sudo apt-get update
sudo apt-get install -y libbz2-dev liblzma-dev
- name: Install project + docs extra
# The package itself (so `import sportsdataverse` works for live
# introspection / executable cells) plus the `docs` extra (great-docs).
run: uv sync --extra docs --extra all --frozen --python 3.13.2
- name: Install Quarto (system dependency)
uses: quarto-dev/quarto-actions/setup@v2
- name: Build Great Docs site
# Non-blocking: the user-guide cells hit the live ESPN API at build time,
# so a transient upstream outage must not red-fail the PR.
continue-on-error: true
env:
PYTHONUTF8: "1"
run: uv run --frozen great-docs build
- name: Upload rendered site
if: always()
uses: actions/upload-artifact@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/great-docs.yml | sed -n '35,70p'

Repository: sportsdataverse/sportsdataverse-py

Length of output: 1710


🌐 Web query:

GitHub Actions security best practices action pinning commit SHA

💡 Result:

Pinning GitHub Actions to a full-length (40-character) commit SHA is a foundational security best practice designed to protect workflows against supply chain attacks [1][2][3]. Why Pinning is Essential GitHub Actions referenced by tags (e.g., @v1) or branches (e.g., @main) are mutable, meaning the code they execute can be changed by anyone with write access to the action's repository [1][4][5]. If an action's repository or a maintainer's account is compromised, attackers can update these tags to point to malicious code, which would then be automatically executed by your workflows [2][6][3]. Pinning to an immutable, full-length commit SHA ensures that your workflows always execute the exact, verified code you intended, regardless of any future changes to the upstream repository [2][4][7]. Best Practices for Implementation - Use Full-Length SHAs: Always use the complete 40-character commit SHA [3][8]. Short SHAs create ambiguity and potential for collisions; full SHAs guarantee unique, deterministic references [8]. - Automate Updates: Manually updating SHAs is error-prone and burdensome [7]. Use automated dependency tools like Dependabot or Renovate to manage updates [6][9]. These tools can be configured to keep your SHAs current while maintaining the security benefits of immutability [6][3]. - Include Human-Readable Comments: When pinning, add a comment in your YAML file with the corresponding version tag (e.g., uses: actions/checkout@sha # v4.2.0) [2][3]. This provides context for human readers and allows automated tools to parse the intended version for future updates [3]. - Enforce via Policy: Administrators can enforce SHA pinning at the repository or organization level through GitHub's allowed actions policy [1][10][4]. When enabled, this policy causes any workflow attempting to use an unpinned (tag-based) action to fail, ensuring consistent security compliance across the organization [10][4][7]. - Audit Dependencies: Pinning only protects the specific action you reference. If that action internally calls other unpinned actions or fetches external dependencies (like Docker images or scripts), those remain potential attack vectors [4][6]. Regularly audit your dependency tree and use security tools like Scorecard, zizmor, or other dedicated scanners to identify insecure practices [4][11][9]. For organizations or projects looking to automate this, tools such as pinact, frizbee, and ratchet are specifically designed to convert existing tag-based references to commit SHAs across your workflow files [4][9].

Citations:


🌐 Web query:

GitHub Actions persist-credentials security implications

💡 Result:

In GitHub Actions, the persist-credentials input for the actions/checkout action controls whether the repository's authentication token (typically the GITHUB_TOKEN) is configured in the local Git environment [1][2][3]. When set to true (the default), this configuration allows subsequent steps in the same job to execute authenticated Git commands—such as git push or git fetch—without needing to manually handle the token [1][4]. Security Implications The primary security risk associated with persist-credentials: true is credential exposure [5][6]. Because the credentials are made available to the Git configuration, any malicious or compromised step, script, or third-party action executed later in the same job can potentially access and abuse these credentials to perform unauthorized API calls or modify the repository [7][5][8]. Specific risks include: - Artifact Leakage: If a workflow uploads the workspace (or its .git directory) as a build artifact, the persisted credentials stored within the Git configuration may be included in the artifact [6][8]. Anyone with access to download these artifacts could then extract the token [8]. - Privilege Abuse: Because the token is available throughout the job, an attacker can use it to perform any action authorized by the token's permissions, which could include modifying repository code or accessing protected assets [5][8]. Recent Improvements Historically, actions/checkout stored these credentials directly in .git/config [6][8]. However, recent versions of actions/checkout (starting with v6) have improved security by storing credentials in a separate file under $RUNNER_TEMP rather than directly in the repository's Git configuration [1][4]. While this change mitigates certain leakage vectors—such as accidental artifact inclusion—it remains best practice to disable this behavior unless it is explicitly required for your workflow's operations [5][8]. Recommendation Unless your workflow requires authenticated Git operations (e.g., pushing commits back to the repository), you should explicitly set persist-credentials: false in your actions/checkout step [5][6]: - uses: actions/checkout@v4 with: persist-credentials: false If you do require authentication, ensure that your GITHUB_TOKEN permissions are configured to follow the principle of least privilege [1][3].

Citations:


Pin actions to commit SHAs and disable credential persistence in checkout.

Actions on lines 39, 41, 57, and 67 are referenced by mutable tags (@v5, @v8.1.0, @v2, @v4) instead of full commit SHAs, which exposes the workflow to supply-chain attacks if these repositories are compromised. Additionally, line 39 relies on the default persist-credentials: true, making the GITHUB_TOKEN available to all subsequent steps—unnecessary here since no authenticated Git operations are performed. Use full 40-character commit SHAs for all action steps and set persist-credentials: false on checkout.

Suggested diff pattern
-      - uses: actions/checkout@v5
+      - uses: actions/checkout@<full_commit_sha>
+        with:
+          persist-credentials: false
...
-      - name: Install uv
-        uses: astral-sh/setup-uv@v8.1.0
+      - name: Install uv
+        uses: astral-sh/setup-uv@<full_commit_sha>
...
-      - name: Install Quarto (system dependency)
-        uses: quarto-dev/quarto-actions/setup@v2
+      - name: Install Quarto (system dependency)
+        uses: quarto-dev/quarto-actions/setup@<full_commit_sha>
...
-      - name: Upload rendered site
-        if: always()
-        uses: actions/upload-artifact@v4
+      - name: Upload rendered site
+        if: always()
+        uses: actions/upload-artifact@<full_commit_sha>
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 39-39: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 39-39: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 41-41: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 57-57: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 67-67: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/great-docs.yml around lines 39 - 67, Replace all mutable
action version tags with full 40-character commit SHAs to prevent supply-chain
attacks: update actions/checkout@v5 to use its pinned SHA,
astral-sh/setup-uv@v8.1.0 to use its pinned SHA,
quarto-dev/quarto-actions/setup@v2 to use its pinned SHA, and
actions/upload-artifact@v4 to use its pinned SHA. Additionally, add
persist-credentials: false to the actions/checkout step configuration since no
authenticated Git operations are performed in this workflow and the GITHUB_TOKEN
does not need to be available to subsequent steps.

Source: Linters/SAST tools

Comment thread pyproject.toml
Comment on lines +104 to +114
docs = [
# Great Docs builds the alternative executable-guides + auto-introspected
# reference site (great-docs.yml + user_guide/*.qmd). It is COMPLEMENTARY to
# the production Docusaurus codegen docs, not a replacement. Docs-only — never
# ships to users. NOTE: Great Docs additionally requires Quarto, which is a
# SYSTEM install (not a pip package) — install it from <https://quarto.org>.
# Marker-gated to py>=3.11 (great-docs requires it); this keeps the package's
# `requires-python = ">=3.9"` runtime support untouched — on 3.9/3.10 the docs
# extra simply resolves without great-docs.
"great-docs>=0.14.0; python_version >= '3.11'",
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read-only verification: confirm the defensive pyjanitor upper bound exists.
rg -nP '^\s*"pyjanitor<0\.32\.18' pyproject.toml

Repository: sportsdataverse/sportsdataverse-py

Length of output: 60


🏁 Script executed:

rg -n 'pyjanitor' pyproject.toml

Repository: sportsdataverse/sportsdataverse-py

Length of output: 163


Add defensive pyjanitor<0.32.18 upper bound to all dependency declarations in pyproject.toml.

All three pyjanitor entries (lines 68, 96, 134) currently have only a lower bound (>=0.23.1). Per coding guidelines, the defensive upper bound must be present until pandas 3 is the project floor, since pyjanitor 0.32.18+ silently switched to pandas 3.x. Update each instance to "pyjanitor>=0.23.1,<0.32.18".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyproject.toml` around lines 104 - 114, The pyjanitor dependency declarations
in pyproject.toml currently have only a lower bound constraint (>=0.23.1)
without an upper bound, which could cause compatibility issues since pyjanitor
0.32.18+ requires pandas 3.x. Locate all three pyjanitor entries in the
dependencies section of pyproject.toml (referenced at lines 68, 96, and 134) and
update each instance by adding the upper bound constraint to read
pyjanitor>=0.23.1,<0.32.18 instead of just the lower bound.

Sources: Coding guidelines, Learnings

Convert docs/docs/tutorials/NN_*.md -> user_guide/NN-*.qmd via
tools/convert_tutorials_to_qmd.py (a build-time authoring tool, not shipped):
- Quarto frontmatter (title/description/jupyter), Docusaurus frontmatter dropped
- code fences -> {python} cells with #| eval: false so the build never hits the
  live ESPN / native / odds / Statcast APIs (fast + non-flaky); each page carries
  a callout pointing at the two executable guides for live output
- internal links rewritten to the Great Docs tree (tutorial cross-links + the
  per-sport reference links collapse to ../reference/index.qmd)

Two explicit user_guide sidebar sections in great-docs.yml: 'User guide' (the
executable getting-started pair, renamed prefix-less so the navbar landing link
resolves) + 'Tutorials' (the 15 ported walkthroughs). Build: 17 user-guide pages,
3 warnings (pre-existing README/CONTRIBUTING), ~2m40s.
Replace the hand-curated reference: block in great-docs.yml with a generated
one. New tools/codegen/great_docs_reference.py enumerates the high-value
espn_<prefix>_<short> entry points per league from tools/codegen/endpoints/
leagues.yaml, emitting only names that are real importable top-level exports of
sportsdataverse, grouped by sport (football/basketball/baseball/hockey/soccer/
cricket). The block is spliced between # >>> / # <<< markers so re-running
refreshes it in place; the NFL-loaders + PBP/config tail sections are preserved.

Wired into generate.py:
  python tools/codegen/generate.py --great-docs          # regenerate
  python tools/codegen/generate.py --great-docs --check  # drift guard (rc=1 if stale)
The drift check also folds into the main --check gate (CI).

Coverage jumps from 8 ESPN sports to 17 league sections — now auto-includes
men's/women's college hockey, college baseball/softball, UFL/XFL/CFL, soccer,
and cricket. Build: 175 reference pages, every generated symbol resolves
(Great Docs introspects them live). splice() emits a single trailing newline so
it agrees with end-of-file-fixer; sys.path shim resolves the local source.
Add a dismissable announcement: banner linking OUT to the interactive docs
(https://py.sportsdataverse.org) — Great Docs is a static Quarto site with no
analogue of the Docusaurus React code playground, so this is the one honest
parity gap. Document the full parity work (brand head, codegen-generated
reference + regen command, tutorials, the playground caveat) in
GREAT-DOCS-NOTES.md and the CLAUDE.md Great Docs subsection.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants