korb 0.2.9__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.
- {korb-0.2.9 → korb-0.3.0}/.github/workflows/release.yml +20 -0
- {korb-0.2.9 → korb-0.3.0}/.github/workflows/test.yml +20 -0
- korb-0.3.0/CHANGELOG.md +191 -0
- {korb-0.2.9 → korb-0.3.0}/PKG-INFO +13 -7
- {korb-0.2.9 → korb-0.3.0}/README.md +10 -5
- korb-0.3.0/docs/coding-standard.md +152 -0
- korb-0.3.0/korb/__init__.py +6 -0
- {korb-0.2.9 → korb-0.3.0}/korb/__main__.py +39 -165
- {korb-0.2.9 → korb-0.3.0}/korb/core.py +70 -18
- korb-0.3.0/korb/download.py +132 -0
- {korb-0.2.9 → korb-0.3.0}/korb/ergebnisse.py +6 -4
- {korb-0.2.9 → korb-0.3.0}/korb/predict.py +66 -86
- {korb-0.2.9 → korb-0.3.0}/korb/schedule.py +31 -22
- korb-0.3.0/korb/standings.py +253 -0
- {korb-0.2.9 → korb-0.3.0}/korb/team.py +14 -6
- {korb-0.2.9 → korb-0.3.0}/pyproject.toml +9 -9
- {korb-0.2.9 → korb-0.3.0}/tests/conftest.py +5 -0
- korb-0.3.0/tests/fixtures/ergebnisse_nested.html +11 -0
- {korb-0.2.9 → korb-0.3.0}/tests/test_cli.py +140 -6
- {korb-0.2.9 → korb-0.3.0}/tests/test_core.py +57 -0
- {korb-0.2.9 → korb-0.3.0}/tests/test_download.py +119 -56
- {korb-0.2.9 → korb-0.3.0}/tests/test_predict.py +33 -0
- {korb-0.2.9 → korb-0.3.0}/tests/test_schedule.py +59 -1
- korb-0.3.0/tests/test_standings.py +190 -0
- {korb-0.2.9 → korb-0.3.0}/tests/test_team.py +61 -0
- korb-0.2.9/CHANGELOG.md +0 -74
- korb-0.2.9/korb/__init__.py +0 -6
- korb-0.2.9/korb/standings.py +0 -164
- korb-0.2.9/tests/test_standings.py +0 -125
- {korb-0.2.9 → korb-0.3.0}/.gitignore +0 -0
- {korb-0.2.9 → korb-0.3.0}/LICENSE +0 -0
- {korb-0.2.9 → korb-0.3.0}/files/.gitkeep +0 -0
- {korb-0.2.9 → korb-0.3.0}/korb/py.typed +0 -0
- {korb-0.2.9 → korb-0.3.0}/tests/__init__.py +0 -0
- {korb-0.2.9 → korb-0.3.0}/tests/fixtures/ergebnisse_minimal.html +0 -0
- {korb-0.2.9 → korb-0.3.0}/tests/fixtures/spielplan_finalized.html +0 -0
- {korb-0.2.9 → korb-0.3.0}/tests/fixtures/spielplan_minimal.html +0 -0
- {korb-0.2.9 → 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
|
korb-0.3.0/CHANGELOG.md
ADDED
|
@@ -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.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: korb
|
|
3
|
-
Version: 0.
|
|
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
|
|
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 &
|
|
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 &
|
|
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
|
|
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 &
|
|
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 &
|
|
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.
|