korb 0.2.8__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {korb-0.2.8 → korb-0.3.0}/.github/workflows/release.yml +20 -0
  2. {korb-0.2.8 → korb-0.3.0}/.github/workflows/test.yml +20 -0
  3. {korb-0.2.8 → korb-0.3.0}/.gitignore +5 -0
  4. korb-0.3.0/CHANGELOG.md +191 -0
  5. {korb-0.2.8 → korb-0.3.0}/PKG-INFO +13 -7
  6. {korb-0.2.8 → korb-0.3.0}/README.md +10 -5
  7. korb-0.3.0/docs/coding-standard.md +152 -0
  8. korb-0.3.0/korb/__init__.py +6 -0
  9. {korb-0.2.8 → korb-0.3.0}/korb/__main__.py +99 -231
  10. {korb-0.2.8 → korb-0.3.0}/korb/core.py +92 -25
  11. korb-0.3.0/korb/download.py +132 -0
  12. {korb-0.2.8 → korb-0.3.0}/korb/ergebnisse.py +6 -4
  13. {korb-0.2.8 → korb-0.3.0}/korb/predict.py +112 -123
  14. {korb-0.2.8 → korb-0.3.0}/korb/schedule.py +55 -76
  15. korb-0.3.0/korb/standings.py +253 -0
  16. {korb-0.2.8 → korb-0.3.0}/korb/team.py +115 -61
  17. {korb-0.2.8 → korb-0.3.0}/pyproject.toml +11 -10
  18. korb-0.3.0/tests/conftest.py +45 -0
  19. korb-0.3.0/tests/fixtures/ergebnisse_nested.html +11 -0
  20. {korb-0.2.8 → korb-0.3.0}/tests/test_cli.py +144 -8
  21. {korb-0.2.8 → korb-0.3.0}/tests/test_core.py +60 -2
  22. {korb-0.2.8 → korb-0.3.0}/tests/test_download.py +119 -56
  23. {korb-0.2.8 → korb-0.3.0}/tests/test_predict.py +42 -9
  24. {korb-0.2.8 → korb-0.3.0}/tests/test_schedule.py +65 -6
  25. korb-0.3.0/tests/test_standings.py +190 -0
  26. korb-0.3.0/tests/test_team.py +194 -0
  27. korb-0.2.8/.coverage +0 -0
  28. korb-0.2.8/CHANGELOG.md +0 -74
  29. korb-0.2.8/korb/__init__.py +0 -6
  30. korb-0.2.8/korb/standings.py +0 -164
  31. korb-0.2.8/tests/conftest.py +0 -22
  32. korb-0.2.8/tests/test_standings.py +0 -125
  33. korb-0.2.8/tests/test_team.py +0 -116
  34. {korb-0.2.8 → korb-0.3.0}/LICENSE +0 -0
  35. {korb-0.2.8 → korb-0.3.0}/files/.gitkeep +0 -0
  36. {korb-0.2.8 → korb-0.3.0}/korb/py.typed +0 -0
  37. {korb-0.2.8 → korb-0.3.0}/tests/__init__.py +0 -0
  38. {korb-0.2.8 → korb-0.3.0}/tests/fixtures/ergebnisse_minimal.html +0 -0
  39. {korb-0.2.8 → korb-0.3.0}/tests/fixtures/spielplan_finalized.html +0 -0
  40. {korb-0.2.8 → korb-0.3.0}/tests/fixtures/spielplan_minimal.html +0 -0
  41. {korb-0.2.8 → korb-0.3.0}/tests/test_ergebnisse.py +0 -0
@@ -29,6 +29,26 @@ jobs:
29
29
  - name: Install dependencies
30
30
  run: uv sync --group dev
31
31
 
32
+ - name: Lint
33
+ if: matrix.python-version == '3.12'
34
+ run: uv run ruff check korb/ tests/
35
+
36
+ - name: Format check
37
+ if: matrix.python-version == '3.12'
38
+ run: uv run ruff format --check korb/ tests/
39
+
40
+ - name: Type check
41
+ if: matrix.python-version == '3.12'
42
+ run: uv run basedpyright korb
43
+
44
+ - name: Complexity budget
45
+ if: matrix.python-version == '3.12'
46
+ run: |
47
+ if uvx radon cc korb -s --show-closures | grep -E '\-\s(C|D|E|F)\s'; then
48
+ echo "::error::Complexity C or worse found"
49
+ exit 1
50
+ fi
51
+
32
52
  - name: Run tests
33
53
  run: uv run pytest -v --tb=short
34
54
 
@@ -26,5 +26,25 @@ jobs:
26
26
  - name: Install dependencies
27
27
  run: uv sync --group dev
28
28
 
29
+ - name: Lint
30
+ if: matrix.python-version == '3.12'
31
+ run: uv run ruff check korb/ tests/
32
+
33
+ - name: Format check
34
+ if: matrix.python-version == '3.12'
35
+ run: uv run ruff format --check korb/ tests/
36
+
37
+ - name: Type check
38
+ if: matrix.python-version == '3.12'
39
+ run: uv run basedpyright korb
40
+
41
+ - name: Complexity budget
42
+ if: matrix.python-version == '3.12'
43
+ run: |
44
+ if uvx radon cc korb -s --show-closures | grep -E '\-\s(C|D|E|F)\s'; then
45
+ echo "::error::Complexity C or worse found"
46
+ exit 1
47
+ fi
48
+
29
49
  - name: Run tests
30
50
  run: uv run pytest -v --tb=short
@@ -6,6 +6,11 @@ __pycache__/
6
6
  dist/
7
7
  build/
8
8
 
9
+ # Coverage
10
+ .coverage
11
+ .coverage.*
12
+ htmlcov/
13
+
9
14
  # Lock file
10
15
  uv.lock
11
16
 
@@ -0,0 +1,191 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/).
6
+
7
+ ## [0.3.0] — 2026-10-25
8
+
9
+ ### Added
10
+
11
+ - `korb/download.py` module with a configurable request timeout and
12
+ shared rate-limit helper.
13
+ - Coverage for cancelled games marked with `title="Spiel abgesagt"`.
14
+ - CLI-level tests for `top`, parser dispatch, download failures, and
15
+ team metrics/bar output.
16
+ - Lint, format, type-check, and complexity gates in CI.
17
+
18
+ ### Changed
19
+
20
+ - Consolidated team-stat updates into `standings.record_game()` and
21
+ standings table rendering into `standings.print_standings_rows()`.
22
+ - `predict` now resolves paths through the shared path helpers and
23
+ parses the results file once.
24
+ - `__main__.py` HTTP/download code moved out; CLI parser construction
25
+ separated from dispatch.
26
+ - `__main__.py` is now included in coverage.
27
+ - JSON key documentation now covers the `ergebnisse` response and
28
+ clarifies that `download` emits no JSON.
29
+ - `print_metrics()` no longer takes a league name (breaking API change).
30
+ - Type annotations added to parser state attributes; ruff targets the
31
+ Python 3.10 floor.
32
+ - Updated the supported DBB target to `12.01.1-f733da5`.
33
+ - Configured basedpyright for CLI-boundary `Any` values and style
34
+ diagnostics so the type-check gate exits cleanly.
35
+
36
+ ### Removed
37
+
38
+ - Unreachable draw branches, the unused `print_metrics(league_name)`
39
+ parameter, and the broken Hatch `features = ["dev"]` environment.
40
+
41
+ ### Fixed
42
+
43
+ - Completed the missing changelog entries for 0.2.4–0.2.9.
44
+ - `download --all` now refreshes leagues in numeric order.
45
+ - Downloads reject empty responses instead of overwriting cached HTML.
46
+ - `schedule --b2b` detects back-to-back games from the full schedule,
47
+ including completed games before a pending fixture, and keeps the
48
+ marker column aligned.
49
+ - Result rows with nested tables inside cells now parse correctly.
50
+ - Malformed rows with a missing `</tr>` no longer discard later rows.
51
+ - `predict` matches completed fixtures by game number, so rescheduled
52
+ games are not counted twice, and treats past-dated unplayed games as
53
+ pending.
54
+ - Parsed names collapse repeated whitespace; team filters normalize
55
+ whitespace and reject empty names.
56
+ - Standings follow DBB placement rules: fewer games, then head-to-head
57
+ points and differential before overall differential.
58
+ - 20:0 and 0:20 results are treated as DBB forfeits and deduct one
59
+ point from the losing team; JSON includes the `penalty` field.
60
+ - Cancelled result rows marked with `title="Spiel abgesagt"` are now
61
+ skipped, matching the schedule parser.
62
+ - `top -n` and `team --last-k` reject non-positive values instead of
63
+ producing misleading output.
64
+
65
+ ---
66
+
67
+ ## [0.2.9] — 2026-07-26
68
+
69
+ ### Changed
70
+
71
+ - Fixed result ordering, improved code quality, and added test coverage.
72
+ - Stopped tracking `.coverage`.
73
+
74
+ ---
75
+
76
+ ## [0.2.8] — 2026-05-11
77
+
78
+ ### Removed
79
+
80
+ - `skill` subcommand and `korb/skills/` package.
81
+
82
+ ### Changed
83
+
84
+ - Replaced black/isort/flake8 with ruff.
85
+ - Rewrote `README.md` for public release and cleaned up inline comments
86
+ and `noqa` annotations.
87
+
88
+ ---
89
+
90
+ ## [0.2.7] — 2026-05-06
91
+
92
+ ### Added
93
+
94
+ - `download --all` / `-a` refreshes all previously downloaded leagues.
95
+ - `discover_league_ids()` scans `files/` for downloaded league IDs.
96
+
97
+ ---
98
+
99
+ ## [0.2.6] — 2026-04-23
100
+
101
+ ### Added
102
+
103
+ - `ergebnisse` subcommand for viewing completed game results.
104
+
105
+ ---
106
+
107
+ ## [0.2.5] — 2026-04-20
108
+
109
+ ### Added
110
+
111
+ - Game dates in per-team results and JSON output.
112
+
113
+ ---
114
+
115
+ ## [0.2.4] — 2026-04-15
116
+
117
+ ### Changed
118
+
119
+ - Schedule output sorted by date.
120
+ - Dead-code and formatting cleanup.
121
+
122
+ ---
123
+
124
+ ## [0.2.3] — 2026-04-10
125
+
126
+ ### Added
127
+
128
+ - `skill` subcommand — prints built-in AI skill prompts to stdout.
129
+ - `skill --list` / `-l` flag — lists available skill names and filenames.
130
+ - `korb/skills/` package with `SKILL_MAP` and `get_skill_text()` using `importlib.resources`.
131
+ - Two bundled skills: `analysis` (team deep-dive) and `prediction` (league top-N forecast).
132
+ - Skill markdown files now shipped inside the `korb` package (included in pip distributions).
133
+
134
+ ### Changed
135
+
136
+ - Migrated `skills/` from project root into `korb/skills/` for proper wheel inclusion.
137
+
138
+ ---
139
+
140
+ ## [0.2.2] — 2026-04-09
141
+
142
+ ### Added
143
+
144
+ - `LeagueInfo` dataclass in `core.py` — bundles league name and Liganr. extracted from HTML.
145
+ - All `--json` outputs now include `liga_name`, `liga_number`, and `ligaid` metadata at the top level.
146
+ - New `extract_league_info()` function parses both league name and `Liganr.: <number>` from DBB HTML.
147
+
148
+ ### Changed
149
+
150
+ - `standings`, `team`, `schedule`, `predict`, and `top` JSON responses are now wrapped objects instead of flat lists, with league metadata and a named data key (`standings`, `results`, `schedule`, `predictions`, `top`).
151
+ - `read_games()`, `calculate_standings()`, `parse_schedule()`, `get_team_results()`, and `predict_standings()` return `LeagueInfo` instead of a bare `str` league name.
152
+
153
+ ---
154
+
155
+ ## [0.2.1] — 2026-04-08
156
+
157
+ ### Changed
158
+
159
+ - Download requests now use browser-spoofing headers (Chrome 131 fingerprint) instead of the plain `korb/<version>` User-Agent to avoid basic bot detection.
160
+ - Added `gzip`/`deflate` response decompression to match the advertised `Accept-Encoding`.
161
+ - Added a random 0.5–1.5 s delay between consecutive HTTP requests to avoid rate-limit triggers.
162
+
163
+ ---
164
+
165
+ ## [0.2.0] — 2026-04-08
166
+
167
+ ### Changed
168
+
169
+ - `--liganr` renamed to `--ligaid` / `-l` and promoted to global flag.
170
+ - `--schedule` / `-s` global flag replaces subcommand-local `--html` on `schedule` and `predict`.
171
+ - `download` subcommand now uses global `--ligaid` instead of a positional argument.
172
+ - Download logic extracted into reusable `_download()` helper.
173
+
174
+ ### Added
175
+
176
+ - `--download` / `-d` global flag — downloads fresh data before running any command.
177
+
178
+ ---
179
+
180
+ ## [0.1.0] — 2026-04-08
181
+
182
+ ### Added
183
+
184
+ - `standings` command — full league table with points, differentials, averages.
185
+ - `team` command — game-by-game results, sparklines, bar chart, quality metrics.
186
+ - `schedule` command — schedule viewer with back-to-back detection, pending/team filters.
187
+ - `predict` command — multiplicative efficiency model for final standings forecast.
188
+ - `top` command — quick leaderboard with ASCII bar chart.
189
+ - `download` command — fetch HTML data from basketball-bund.net.
190
+ - `--json` flag for machine-readable output on all commands.
191
+ - `--version` flag.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: korb
3
- Version: 0.2.8
3
+ Version: 0.3.0
4
4
  Summary: A CLI toolkit for DBB basketball league analysis
5
5
  Project-URL: Homepage, https://github.com/malvavisc0/korb
6
6
  Project-URL: Repository, https://github.com/malvavisc0/korb
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
21
22
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
22
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
24
  Requires-Python: >=3.10
@@ -49,7 +50,7 @@ platform and provides standings, results, schedules, predictions, and more.
49
50
  - 🔮 **Predict** — efficiency-model-based final standings forecast
50
51
  - 🥇 **Top** — quick leaderboard with ASCII bar chart
51
52
  - 📥 **Download** — fetch fresh HTML data directly from basketball-bund.net
52
- - 🔧 **`--json`** — machine-readable output for all commands
53
+ - 🔧 **`--json`** — machine-readable output for data commands (not `download`)
53
54
 
54
55
  ## Installation
55
56
 
@@ -58,7 +59,7 @@ platform and provides standings, results, schedules, predictions, and more.
58
59
  git clone https://github.com/malvavisc0/korb && cd korb
59
60
  uv sync
60
61
 
61
- # With pip
62
+ # With pip (end-user install)
62
63
  pip install .
63
64
  ```
64
65
 
@@ -169,8 +170,9 @@ The `predict` command estimates final standings using a **multiplicative efficie
169
170
  ```
170
171
  korb/
171
172
  ├── __init__.py # Package marker & version
172
- ├── __main__.py # CLI entry point & download command
173
+ ├── __main__.py # CLI entry point & command handlers
173
174
  ├── core.py # Shared models, HTML parsing, utilities
175
+ ├── download.py # HTTP downloader, headers, rate limiting
174
176
  ├── ergebnisse.py # Game results viewer & filter
175
177
  ├── predict.py # Multiplicative efficiency prediction model
176
178
  ├── schedule.py # HTML schedule parser & filters
@@ -190,14 +192,18 @@ korb/
190
192
  # Install with dev tools
191
193
  uv sync --group dev
192
194
 
193
- # Lint & format
195
+ # Lint, format & type-check
194
196
  uv run ruff check korb/ tests/
195
197
  uv run ruff format korb/ tests/
198
+ uv run basedpyright korb
196
199
 
197
200
  # Run tests
198
201
  uv run pytest
199
202
  ```
200
203
 
204
+ Project conventions are documented in
205
+ [`docs/coding-standard.md`](docs/coding-standard.md).
206
+
201
207
  ## License
202
208
 
203
- [MIT](LICENSE)
209
+ [MIT](LICENSE)
@@ -24,7 +24,7 @@ platform and provides standings, results, schedules, predictions, and more.
24
24
  - 🔮 **Predict** — efficiency-model-based final standings forecast
25
25
  - 🥇 **Top** — quick leaderboard with ASCII bar chart
26
26
  - 📥 **Download** — fetch fresh HTML data directly from basketball-bund.net
27
- - 🔧 **`--json`** — machine-readable output for all commands
27
+ - 🔧 **`--json`** — machine-readable output for data commands (not `download`)
28
28
 
29
29
  ## Installation
30
30
 
@@ -33,7 +33,7 @@ platform and provides standings, results, schedules, predictions, and more.
33
33
  git clone https://github.com/malvavisc0/korb && cd korb
34
34
  uv sync
35
35
 
36
- # With pip
36
+ # With pip (end-user install)
37
37
  pip install .
38
38
  ```
39
39
 
@@ -144,8 +144,9 @@ The `predict` command estimates final standings using a **multiplicative efficie
144
144
  ```
145
145
  korb/
146
146
  ├── __init__.py # Package marker & version
147
- ├── __main__.py # CLI entry point & download command
147
+ ├── __main__.py # CLI entry point & command handlers
148
148
  ├── core.py # Shared models, HTML parsing, utilities
149
+ ├── download.py # HTTP downloader, headers, rate limiting
149
150
  ├── ergebnisse.py # Game results viewer & filter
150
151
  ├── predict.py # Multiplicative efficiency prediction model
151
152
  ├── schedule.py # HTML schedule parser & filters
@@ -165,14 +166,18 @@ korb/
165
166
  # Install with dev tools
166
167
  uv sync --group dev
167
168
 
168
- # Lint & format
169
+ # Lint, format & type-check
169
170
  uv run ruff check korb/ tests/
170
171
  uv run ruff format korb/ tests/
172
+ uv run basedpyright korb
171
173
 
172
174
  # Run tests
173
175
  uv run pytest
174
176
  ```
175
177
 
178
+ Project conventions are documented in
179
+ [`docs/coding-standard.md`](docs/coding-standard.md).
180
+
176
181
  ## License
177
182
 
178
- [MIT](LICENSE)
183
+ [MIT](LICENSE)
@@ -0,0 +1,152 @@
1
+ # Python Developer AI Agent
2
+
3
+ ## Communication
4
+ You are talking to seniors. Be terse — no preamble, no recap, no
5
+ hand-holding, no "here's what I did" summaries. State results, not
6
+ intentions. Skip explanations unless explicitly asked. Never narrate
7
+ tool use. Answer the question; move on.
8
+
9
+ ## Project
10
+ korb — a zero-runtime-dependency Python CLI for DBB (Deutscher
11
+ Basketball Bund) basketball league analysis. It parses HTML from the
12
+ legacy JSP platform at basketball-bund.net (target: DBB Version
13
+ ≤12.01.1-f733da5) and exposes standings, results, schedules,
14
+ predictions, and team metrics. An argparse CLI (`korb/__main__.py`)
15
+ dispatches subcommands; `korb/download.py` fetches fresh league HTML
16
+ into `files/<ligaid>/`.
17
+
18
+ ## Stack
19
+ - Python 3.10+ (CI covers 3.10–3.14), uv, pyproject.toml (hatchling,
20
+ flat `korb/` package layout)
21
+ - Zero runtime dependencies: standard library only (`argparse`,
22
+ `html.parser`, `urllib`, `dataclasses`, `zoneinfo`)
23
+ - Dev dependencies: pytest, pytest-cov, ruff, basedpyright
24
+ - CLI: argparse subcommands in `korb/__main__.py`, entry point
25
+ `korb = "korb.__main__:main"`
26
+ - Type checker: **basedpyright** (configured in pyproject; CLI-boundary
27
+ `Any` and style diagnostics disabled)
28
+ - Lint/format: **ruff** (line-length 88, target py310 — the minimum
29
+ supported Python)
30
+ - Complexity: **radon** (ad hoc via `uvx`)
31
+ - Dead code: **vulture** (advisory; no config yet)
32
+ - Packaging: hatchling; version lives in `korb/__init__.py`
33
+
34
+ ## Commands
35
+ ```bash
36
+ uv sync --group dev
37
+ uv run korb --help
38
+ uv run korb --ligaid 12345 download
39
+ uv run ruff check --fix korb/ tests/
40
+ uv run ruff format korb/ tests/
41
+ uv run basedpyright korb
42
+ uvx radon cc korb -s --show-closures
43
+ uvx vulture korb tests --min-confidence 60
44
+ uv run pytest
45
+ ```
46
+ Run `ruff check`, `ruff format --check`, `basedpyright`, and `pytest`
47
+ after every change. `basedpyright` must report zero errors; do not add
48
+ new warnings. CI runs the same gates plus the radon complexity check.
49
+
50
+ ## Complexity budget
51
+ `radon cc` must report **no block ranked C or worse** — every
52
+ function/method stays at rank A or B (complexity ≤ 10). This applies to
53
+ the whole codebase: a pre-existing C+ block is still a defect and must
54
+ be fixed in the same pass (early returns, extract helpers, dispatch
55
+ tables). Verify with:
56
+ ```bash
57
+ uvx radon cc korb -s --show-closures | grep -E '\-\s(C|D|E|F)\s' # must be empty
58
+ ```
59
+
60
+ ## Dead code
61
+ No dead code. Vulture is not configured here, and its hits on
62
+ `HTMLParser.handle_*` callbacks, pytest fixtures, and `unittest.mock`
63
+ attributes are false positives — never delete those. Treat every other
64
+ hit as a suspect: check for a registration site before deleting. Real
65
+ dead code (never-read fields, zero-call-site functions) goes out in the
66
+ same pass. If vulture becomes a gate, add `[tool.vulture]` to
67
+ pyproject.toml and make the default run clean.
68
+
69
+ ## PII
70
+ Never use or commit PII — not in code, tests, docs, plans, fixtures,
71
+ examples, commit messages, or changelog entries. PII is any real
72
+ person's data: names, contact details, message bodies, transcripts,
73
+ trace/session ids tied to a person. Rules:
74
+
75
+ - Tests, docstrings, and examples use fictional identities only.
76
+ Fixtures use synthetic leagues, teams, and scores ("Test
77
+ Bezirksliga", "Team Alpha", `Liganr.: 99999`), never a real league
78
+ export.
79
+ - Downloaded HTML contains real league data; it stays in the ignored
80
+ `files/<ligaid>/` tree and never enters git.
81
+ - Before committing anything derived from a real export, grep the diff
82
+ for names you saw in it: `git diff | rg -i "<name>"`. If it came from
83
+ an export, it does not go in the repo.
84
+
85
+ ## Priority
86
+ Clean, simple, maintainable code. Nothing else.
87
+
88
+ ## Commits
89
+ One-line messages only. No body, no trailers.
90
+
91
+ ## Rules
92
+ - DRY, KISS
93
+ - Zero runtime dependencies — stdlib first, no new dependency without
94
+ an explicit decision
95
+ - No unnecessary complexity
96
+ - No defensive fallbacks / over-engineering
97
+ - Explicit > implicit
98
+ - Type hints for all `korb/` code (the hatch-parsed `__version__`
99
+ constant is the exception). Tests follow pytest conventions and need
100
+ not be fully annotated
101
+ - Python ≥3.10 syntax and stdlib only (CI runs 3.10 through 3.14)
102
+ - PEP 8 (ruff enforces, line-length 88)
103
+ - Meaningful names, small functions
104
+ - Fail fast and clearly: user-facing errors go to stderr and exit 1.
105
+ Malformed HTML table rows are the one intentional exception: parsers
106
+ skip them so one bad row does not discard an entire league
107
+ - No clever tricks
108
+ - Docstrings for public APIs
109
+ - No unnecessary inline comments
110
+ - Use uv for development and CI (never pip / system python). README may
111
+ document pip for end users
112
+ - No mutable module-level state. Read-only constants (`HEADERS`, URL
113
+ templates, point values) are fine; never mutate them at runtime
114
+ - Module-local helpers take a leading underscore; anything imported by
115
+ production code is public. Tests may import private helpers for
116
+ focused unit tests. `core.py` is the shared-helper home
117
+ - No dead code
118
+ - No Python file over 600 lines in `korb/` or `tests/`
119
+
120
+ ## Style
121
+ Write the simplest correct solution. Delete anything that isn't needed.
122
+
123
+ ## Conventions
124
+ - Commands live in `korb/__main__.py`: a `cmd_<name>(args)` handler
125
+ plus an argparse subparser in `main()` wired with
126
+ `set_defaults(func=cmd_<name>)`. Global flags are `--results`,
127
+ `--schedule`, `--json`, `--ligaid`, `--download`.
128
+ - Feature modules sit next to the CLI (`standings.py`, `team.py`,
129
+ `schedule.py`, `predict.py`, `ergebnisse.py`, `download.py`); shared
130
+ models, HTML parsing, date/score helpers, and output headers live in
131
+ `core.py`.
132
+ - HTML parsing extends the shared public `DBBRowParser`
133
+ (`<td>`/`<tr>`/`<strike>` state machine). Parser changes need a
134
+ fixture in `tests/fixtures/` and a test; cover cancelled rows
135
+ (`<strike>`, `title="Spiel abgesagt"`) and finalized schedules.
136
+ - Parsers return `(data, LeagueInfo)`. Every data command's `--json`
137
+ response is a wrapped object built with `_liga_meta(...)` plus a
138
+ named data key: `standings`, `results` (team), `ergebnisse`,
139
+ `schedule`, `predictions`, and `top`. `download` is a side-effect
140
+ command and emits no JSON.
141
+ - Data paths resolve as `files/<ligaid>/ergebnisse.html` and
142
+ `files/<ligaid>/spielplan.html`; explicit `--results` / `--schedule`
143
+ win. Use `_resolve_results` / `_resolve_schedule`, not ad hoc paths.
144
+ - Downloads live in `korb/download.py` and must keep the
145
+ browser-spoofing headers, gzip/deflate handling, a request timeout,
146
+ and the 1–3 s delay between requests; the legacy host rate-limits.
147
+ Reference: https://www.basketball-bund.net
148
+ - Bump `__version__` in `korb/__init__.py` and update `CHANGELOG.md`
149
+ for user-visible changes. Release tags (`v*`) must match the version.
150
+ - Tests: one file per module (`tests/test_<module>.py`), pytest with
151
+ coverage enabled by default in `pyproject.toml`. New CLI commands
152
+ need command-level tests, not only module-level unit tests.
@@ -0,0 +1,6 @@
1
+ """Basketball league analysis package for DBB (Deutscher Basketball Bund).
2
+
3
+ Target: DBB Version ≤12.01.1-f733da5 (legacy JSP platform).
4
+ """
5
+
6
+ __version__ = "0.3.0"