| name | sdv-preflight |
| description | Use for a fast local sanity sweep on the current changes in sportsdataverse-py (sdv-py) before committing or opening a PR — runs ruff, the mypy ratchet, and the relevant tests scoped to changed files only (not the whole suite). Invoke for "preflight", "quick check before commit", "lint+type+test my changes", or "is this ready to push". |
Preflight — fast checks on changed files
A quick, scoped sweep that mirrors what CI will check, but only over what you
changed — seconds, not a full pytest. Use it before a commit/PR for fast
feedback; use /sdv-ship for the full release-gate flow.
Steps
-
Find changed Python files (staged + unstaged + untracked):
git status --porcelain | sed 's/^...//; s/.* -> //' | grep -E '\.py$'
New module? Shadow check first. If the change ADDS a new
sportsdataverse/**/<name>.py, confirm the filename doesn't collide with an
existing symbol in the target package (star-imported wrapper, generated
function, loader). A module that shares a name with a released function
rebinds the package attribute — existing callers get
TypeError: 'module' object is not callable. This has shipped twice
(nba_possessions, nfl_standings):
grep -rn "\b<name>\b" sportsdataverse/<pkg>/__init__.py
uv run python -c "import sportsdataverse.<pkg> as p; print(type(getattr(p, '<name>', None)))"
If it collides, rename the module file (e.g. <name>_calc.py) — the public
function inside can keep its name; only the filename collides.
-
Ruff — format + lint the changed files (the PostToolUse hook already
formats on edit; this catches anything edited outside Claude):
uv run ruff format <changed.py ...>
uv run ruff check <changed.py ...>
-
mypy ratchet — only if a changed file is in the [tool.mypy] files
ratchet in pyproject.toml. mypy with no args checks the curated list
(follow_imports = "skip" → sub-second):
uv run mypy
-
Targeted tests — map each changed module to its test dir and run only
those, rather than the whole suite. For a changed
sportsdataverse/<sport>/<mod>.py, run tests/<sport>/:
uv run pytest tests/<sport>/ -q
If the change is cross-cutting (e.g. dl_utils.py, _common_espn*.py,
config.py) or the mapping is unclear, fall back to the full suite
(uv run pytest -q) and say so. Live-API tests stay skipped unless
SDV_PY_LIVE_TESTS=1.
Always also run the ID / name-matching contract — a sub-second offline guard
for the recurring int-vs-str / id→Utf8 / case-sensitive-regex bug class:
uv run pytest tests/test_id_conventions.py -q
-
Report a one-line verdict per stage (ruff / mypy / tests: pass|fail) and,
on any failure, the specific file:line. This is a sanity sweep — surface
problems, don't auto-fix beyond ruff's own --fix.
When to escalate
If preflight is green and you're about to release or merge, switch to /sdv-ship
(full pytest + codegen drift + CI-green + merge-confirm). Preflight is the fast
inner-loop check; /sdv-ship is the gate.