Skip to content

v2.0.1 — packaging fix for v2.0.0

Latest

Choose a tag to compare

@MaverickHQ MaverickHQ released this 21 Jun 10:15
· 1 commit to main since this release

Packaging-only patch. No runtime code changed. v2.0.0 → v2.0.1 fixes two latent defects that have been present since v1.0.0 but only surface when installing from PyPI (not from git clone, which is how this repo is normally deployed).

What was broken in v2.0.0

pip install player-coach-core==2.0.0 produced a package where:

  1. player_coach/artifacts/ was missing entirely from the wheel. Any from player_coach.loop.coach_loop import CoachLoop chained through player_coach.artifacts.writer.ArtifactWriter and crashed with ModuleNotFoundError.
  2. yfinance wasn't declared in any extra. Even pip install player-coach-core[market] (which had numpy, hmmlearn, arch) couldn't import BacktestRunner — yfinance is needed for OHLCV fetching at module level.

Neither bug was caught by the existing 513-test suite because development happens from git clone where requirements.txt covers everything. They were caught during the post-publish smoke test on a clean venv.

Fixes

Defect Cause Fix
D1player_coach/artifacts/ missing from wheel .gitignore:12 had unanchored artifacts/ — hatchling's pathspec parser matched the Python sub-module too, even though git check-ignore correctly said it wasn't ignored .gitignore: artifacts//artifacts/ (anchor to repo root)
D2yfinance not declared [project.optional-dependencies.market] listed numpy, hmmlearn, arch — yfinance was missed pyproject.toml [market]: add yfinance>=0.2.40

TDD coverage added

Two new tests in tests/unit/test_packaging.py pin both defects so they cannot regress:

  • test_no_tracked_player_coach_file_matches_gitignore — walks git ls-files player_coach/ and asserts no path is matched by any .gitignore pattern under hatchling-equivalent semantics. Would have failed on v2.0.0.
  • test_declared_dependencies_cover_runtime_imports — AST-parses every player_coach/**/*.py, asserts every non-stdlib top-level import is in [dependencies] or an [optional-dependencies] table. Would have failed on v2.0.0.

Plus two guardrail tests that were already passing and remain unchanged:

  • test_pyproject_declares_llm_extra_for_anthropic — pins the CLAUDE.md install ladder
  • test_tomllib_available — pins the Python 3.11+ floor needed for the static analysis above

Stale test removed

test_python_version_pinned_for_streamlit_cloud (in tests/unit/test_requirements.py) was pinning the .python-version file we removed in ee586d5. That file turned out to be a pyenv-only convention that Streamlit Cloud ignores (Cloud reads its Python version from the per-app Settings UI, not from any repo file). The test was pinning a contract that no longer applies; the deploy-mechanism docs moved to CLAUDE.md's "Deploy environment" section.

Verification

# clean venv, install from PyPI
python3 -m venv /tmp/v
/tmp/v/bin/pip install 'player-coach-core[market,llm]==2.0.1'

# the v2.0.0-broken import chain
/tmp/v/bin/python -c "
from player_coach.loop.coach_loop import CoachLoop
from player_coach.backtest.runner import BacktestRunner
from player_coach.artifacts.writer import ArtifactWriter   # was missing in v2.0.0
print('all imports OK')
"

Test count
513 → 516 (+4 new packaging tests, –1 stale .python-version test = +3 net), 1 skipped, lint clean.

Who needs to upgrade
pip install player-coach-core users — yes, upgrade. v2.0.0 is fundamentally broken on import.
Streamlit Cloud users (this app's actual deploy path) — no change needed. Cloud reads from git, not PyPI.
git clone developers — no change needed; requirements.txt was always covering this.
Installation

pip install --upgrade 'player-coach-core[market,llm]==2.0.1'

---

## Why this body is shorter than v2.0.0's

v2.0.0 shipped features. v2.0.1 ships a packaging correction. The body reflects that — single section per defect, the TDD evidence, verification recipe, and a clear "who needs to upgrade" guide. ~50 lines instead of 100.

Ping me when the GitHub Release is published. The background install will notify me when it finishes (~2 min from when I started it).