backcaster 0.3.1__tar.gz → 0.3.3__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.
- {backcaster-0.3.1/src/backcaster.egg-info → backcaster-0.3.3}/PKG-INFO +48 -30
- {backcaster-0.3.1 → backcaster-0.3.3}/README.md +46 -27
- {backcaster-0.3.1 → backcaster-0.3.3}/pyproject.toml +2 -3
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/__init__.py +1 -1
- backcaster-0.3.3/src/backcaster/cli.py +86 -0
- backcaster-0.3.3/src/backcaster/data.py +9 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/lahman.py +4 -1
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/marcel.py +7 -2
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/schemas.py +0 -1
- {backcaster-0.3.1 → backcaster-0.3.3/src/backcaster.egg-info}/PKG-INFO +48 -30
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/SOURCES.txt +1 -4
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/requires.txt +0 -1
- backcaster-0.3.3/tests/test_cli.py +102 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_lahman.py +27 -2
- {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_marcel_math.py +49 -0
- backcaster-0.3.1/src/backcaster/cli.py +0 -176
- backcaster-0.3.1/src/backcaster/data.py +0 -246
- backcaster-0.3.1/tests/test_cli.py +0 -259
- backcaster-0.3.1/tests/test_cli_player_lookup.py +0 -60
- backcaster-0.3.1/tests/test_data.py +0 -412
- backcaster-0.3.1/tests/test_player_lookup.py +0 -89
- {backcaster-0.3.1 → backcaster-0.3.3}/LICENSE +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/setup.cfg +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/normalize.py +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/outputs.py +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/dependency_links.txt +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/entry_points.txt +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/top_level.txt +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_normalize.py +0 -0
- {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_outputs.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: backcaster
|
|
3
|
-
Version: 0.3.
|
|
4
|
-
Summary: Marcel-style MLB projection CLI
|
|
3
|
+
Version: 0.3.3
|
|
4
|
+
Summary: Marcel-style MLB projection CLI using local Lahman CSV data
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/jeffreywevans/backcaster
|
|
7
7
|
Project-URL: Repository, https://github.com/jeffreywevans/backcaster
|
|
@@ -18,7 +18,6 @@ Requires-Python: >=3.13
|
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: pandas>=2.0
|
|
21
|
-
Requires-Dist: pybaseball>=2.2
|
|
22
21
|
Provides-Extra: dev
|
|
23
22
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
24
23
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
@@ -30,7 +29,7 @@ Dynamic: license-file
|
|
|
30
29
|
|
|
31
30
|
# Backcaster
|
|
32
31
|
|
|
33
|
-
Backcaster is a Python CLI that produces **Marcel-style MLB projections** from the prior three seasons of data using
|
|
32
|
+
Backcaster is a Python CLI that produces **Marcel-style MLB projections** from the prior three seasons of data using local Lahman CSV files and `pandas`.
|
|
34
33
|
|
|
35
34
|
It supports:
|
|
36
35
|
- **Single player projections** (`player`)
|
|
@@ -44,7 +43,29 @@ It supports:
|
|
|
44
43
|
|
|
45
44
|
### Requirements
|
|
46
45
|
- Python **3.13+**
|
|
47
|
-
-
|
|
46
|
+
- An extracted Lahman CSV database covering the three prior seasons
|
|
47
|
+
- Internet access for package installation only; projections run offline
|
|
48
|
+
|
|
49
|
+
### Update an installed package
|
|
50
|
+
|
|
51
|
+
Upgrade to the latest release available on PyPI:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
python -m pip install --upgrade backcaster
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
To install a specific release, such as 0.3.3:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
python -m pip install --upgrade backcaster==0.3.3
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Run the command using the same Python environment where you run Backcaster.
|
|
64
|
+
If you use a virtual environment, activate it first. Check the installed version with:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
python -m pip show backcaster
|
|
68
|
+
```
|
|
48
69
|
|
|
49
70
|
### Install from source (recommended for contributors)
|
|
50
71
|
|
|
@@ -95,12 +116,23 @@ backcaster player --name "Mookie Betts" --year 2026 --kind batting
|
|
|
95
116
|
|
|
96
117
|
### Offline projections with Lahman CSVs
|
|
97
118
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
119
|
+
All projections use local Lahman CSVs. On Windows, the default directory is
|
|
120
|
+
`C:\Baseball\lahman`; on other systems it is `~/Baseball/lahman`.
|
|
121
|
+
Set the `LAHMAN_DATA_DIR` environment variable to change the default, or pass
|
|
122
|
+
`--data-dir` to override it for one command. No network requests or online
|
|
123
|
+
fallbacks are made. The directory must contain `People.csv`, `Teams.csv`, and
|
|
101
124
|
`Batting.csv` or `Pitching.csv` for the selected kind. Filenames are matched
|
|
102
125
|
without regard to case. The database is not bundled with Backcaster.
|
|
103
126
|
|
|
127
|
+
For the default Windows directory, no additional flag is needed:
|
|
128
|
+
|
|
129
|
+
```powershell
|
|
130
|
+
backcaster player --name "Mookie Betts" --year 2024 --kind batting
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
See [Lahman database notes](docs/LAHMAN.md) for the supplied 1871–2025 edition's
|
|
134
|
+
coverage, attribution, license, and historical-data caveats, with its original README.
|
|
135
|
+
|
|
104
136
|
```powershell
|
|
105
137
|
backcaster player --name "Mookie Betts" --year 2022 --kind batting --data-dir "C:\Baseball\lahman"
|
|
106
138
|
backcaster team --team LAN --year 2022 --kind batting --data-dir "C:\Baseball\lahman"
|
|
@@ -110,8 +142,8 @@ backcaster batch --year 2022 --kind pitching --data-dir "C:\Baseball\lahman" --f
|
|
|
110
142
|
Use Lahman's `teamID` values, such as `LAN` for the Dodgers (rather than the
|
|
111
143
|
FanGraphs abbreviation `LAD`). A projection year needs the preceding three seasons:
|
|
112
144
|
2022 requires 2019–2021. Missing seasons produce an error explaining which year
|
|
113
|
-
is unavailable.
|
|
114
|
-
|
|
145
|
+
is unavailable. If the directory or required files are missing, the command
|
|
146
|
+
reports the missing file and directory; it never attempts an online fetch.
|
|
115
147
|
|
|
116
148
|
Offline qualification uses a consistent modern rule across historical seasons:
|
|
117
149
|
at least **3.1 PA per game** for hitters and **one inning per game** for pitchers.
|
|
@@ -138,7 +170,7 @@ to the team in their latest stint for that season; this is not a current-roster
|
|
|
138
170
|
### 2) Team projection
|
|
139
171
|
|
|
140
172
|
```bash
|
|
141
|
-
backcaster team --team
|
|
173
|
+
backcaster team --team LAN --year 2026 --kind pitching
|
|
142
174
|
```
|
|
143
175
|
|
|
144
176
|
### 3) Batch projection (all players returned by source data)
|
|
@@ -151,7 +183,7 @@ backcaster batch --year 2026 --kind batting
|
|
|
151
183
|
|
|
152
184
|
```bash
|
|
153
185
|
backcaster player --name "Mookie Betts" --year 2026 --kind batting --format csv --out ./out/mookie_2026.csv
|
|
154
|
-
backcaster team --team
|
|
186
|
+
backcaster team --team LAN --year 2026 --kind pitching --format html --out ./out/lan_pitching_2026.html
|
|
155
187
|
```
|
|
156
188
|
|
|
157
189
|
> `--out` is required for `csv` and `html` formats.
|
|
@@ -177,24 +209,11 @@ A basic HTML table (no custom CSS) suitable for quick sharing or embedding.
|
|
|
177
209
|
|
|
178
210
|
---
|
|
179
211
|
|
|
180
|
-
##
|
|
181
|
-
|
|
182
|
-
Backcaster caches season stat pulls under:
|
|
183
|
-
|
|
184
|
-
```text
|
|
185
|
-
~/.cache/backcaster/
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Cache details:
|
|
189
|
-
- Key pattern: `<kind>_<year>.parquet` (preferred) or `<kind>_<year>.csv` (fallback)
|
|
190
|
-
- Read order: Parquet first, then CSV
|
|
191
|
-
- Write behavior: atomic temp-file write + rename to reduce corruption risk
|
|
192
|
-
- Parquet write failures automatically fall back to CSV
|
|
212
|
+
## Local data updates
|
|
193
213
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
- If upstream data changes and you need a refresh, delete the relevant cache file(s) and rerun.
|
|
214
|
+
Backcaster reads the local CSV files for each command and does not use the old
|
|
215
|
+
FanGraphs season cache. To refresh the data, replace the CSVs with a complete
|
|
216
|
+
Lahman distribution from the same edition. Existing online caches are ignored.
|
|
198
217
|
|
|
199
218
|
---
|
|
200
219
|
|
|
@@ -202,7 +221,6 @@ Practical implications:
|
|
|
202
221
|
|
|
203
222
|
Runtime dependencies are intentionally minimal:
|
|
204
223
|
- `pandas` for tabular data processing and projection output
|
|
205
|
-
- `pybaseball` for MLB player/team seasonal stat retrieval and player ID lookup
|
|
206
224
|
|
|
207
225
|
Development dependencies (`--extra dev`) include:
|
|
208
226
|
- `pytest`, `pytest-cov`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Backcaster
|
|
2
2
|
|
|
3
|
-
Backcaster is a Python CLI that produces **Marcel-style MLB projections** from the prior three seasons of data using
|
|
3
|
+
Backcaster is a Python CLI that produces **Marcel-style MLB projections** from the prior three seasons of data using local Lahman CSV files and `pandas`.
|
|
4
4
|
|
|
5
5
|
It supports:
|
|
6
6
|
- **Single player projections** (`player`)
|
|
@@ -14,7 +14,29 @@ It supports:
|
|
|
14
14
|
|
|
15
15
|
### Requirements
|
|
16
16
|
- Python **3.13+**
|
|
17
|
-
-
|
|
17
|
+
- An extracted Lahman CSV database covering the three prior seasons
|
|
18
|
+
- Internet access for package installation only; projections run offline
|
|
19
|
+
|
|
20
|
+
### Update an installed package
|
|
21
|
+
|
|
22
|
+
Upgrade to the latest release available on PyPI:
|
|
23
|
+
|
|
24
|
+
```powershell
|
|
25
|
+
python -m pip install --upgrade backcaster
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
To install a specific release, such as 0.3.3:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
python -m pip install --upgrade backcaster==0.3.3
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Run the command using the same Python environment where you run Backcaster.
|
|
35
|
+
If you use a virtual environment, activate it first. Check the installed version with:
|
|
36
|
+
|
|
37
|
+
```powershell
|
|
38
|
+
python -m pip show backcaster
|
|
39
|
+
```
|
|
18
40
|
|
|
19
41
|
### Install from source (recommended for contributors)
|
|
20
42
|
|
|
@@ -65,12 +87,23 @@ backcaster player --name "Mookie Betts" --year 2026 --kind batting
|
|
|
65
87
|
|
|
66
88
|
### Offline projections with Lahman CSVs
|
|
67
89
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
90
|
+
All projections use local Lahman CSVs. On Windows, the default directory is
|
|
91
|
+
`C:\Baseball\lahman`; on other systems it is `~/Baseball/lahman`.
|
|
92
|
+
Set the `LAHMAN_DATA_DIR` environment variable to change the default, or pass
|
|
93
|
+
`--data-dir` to override it for one command. No network requests or online
|
|
94
|
+
fallbacks are made. The directory must contain `People.csv`, `Teams.csv`, and
|
|
71
95
|
`Batting.csv` or `Pitching.csv` for the selected kind. Filenames are matched
|
|
72
96
|
without regard to case. The database is not bundled with Backcaster.
|
|
73
97
|
|
|
98
|
+
For the default Windows directory, no additional flag is needed:
|
|
99
|
+
|
|
100
|
+
```powershell
|
|
101
|
+
backcaster player --name "Mookie Betts" --year 2024 --kind batting
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
See [Lahman database notes](docs/LAHMAN.md) for the supplied 1871–2025 edition's
|
|
105
|
+
coverage, attribution, license, and historical-data caveats, with its original README.
|
|
106
|
+
|
|
74
107
|
```powershell
|
|
75
108
|
backcaster player --name "Mookie Betts" --year 2022 --kind batting --data-dir "C:\Baseball\lahman"
|
|
76
109
|
backcaster team --team LAN --year 2022 --kind batting --data-dir "C:\Baseball\lahman"
|
|
@@ -80,8 +113,8 @@ backcaster batch --year 2022 --kind pitching --data-dir "C:\Baseball\lahman" --f
|
|
|
80
113
|
Use Lahman's `teamID` values, such as `LAN` for the Dodgers (rather than the
|
|
81
114
|
FanGraphs abbreviation `LAD`). A projection year needs the preceding three seasons:
|
|
82
115
|
2022 requires 2019–2021. Missing seasons produce an error explaining which year
|
|
83
|
-
is unavailable.
|
|
84
|
-
|
|
116
|
+
is unavailable. If the directory or required files are missing, the command
|
|
117
|
+
reports the missing file and directory; it never attempts an online fetch.
|
|
85
118
|
|
|
86
119
|
Offline qualification uses a consistent modern rule across historical seasons:
|
|
87
120
|
at least **3.1 PA per game** for hitters and **one inning per game** for pitchers.
|
|
@@ -108,7 +141,7 @@ to the team in their latest stint for that season; this is not a current-roster
|
|
|
108
141
|
### 2) Team projection
|
|
109
142
|
|
|
110
143
|
```bash
|
|
111
|
-
backcaster team --team
|
|
144
|
+
backcaster team --team LAN --year 2026 --kind pitching
|
|
112
145
|
```
|
|
113
146
|
|
|
114
147
|
### 3) Batch projection (all players returned by source data)
|
|
@@ -121,7 +154,7 @@ backcaster batch --year 2026 --kind batting
|
|
|
121
154
|
|
|
122
155
|
```bash
|
|
123
156
|
backcaster player --name "Mookie Betts" --year 2026 --kind batting --format csv --out ./out/mookie_2026.csv
|
|
124
|
-
backcaster team --team
|
|
157
|
+
backcaster team --team LAN --year 2026 --kind pitching --format html --out ./out/lan_pitching_2026.html
|
|
125
158
|
```
|
|
126
159
|
|
|
127
160
|
> `--out` is required for `csv` and `html` formats.
|
|
@@ -147,24 +180,11 @@ A basic HTML table (no custom CSS) suitable for quick sharing or embedding.
|
|
|
147
180
|
|
|
148
181
|
---
|
|
149
182
|
|
|
150
|
-
##
|
|
151
|
-
|
|
152
|
-
Backcaster caches season stat pulls under:
|
|
153
|
-
|
|
154
|
-
```text
|
|
155
|
-
~/.cache/backcaster/
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Cache details:
|
|
159
|
-
- Key pattern: `<kind>_<year>.parquet` (preferred) or `<kind>_<year>.csv` (fallback)
|
|
160
|
-
- Read order: Parquet first, then CSV
|
|
161
|
-
- Write behavior: atomic temp-file write + rename to reduce corruption risk
|
|
162
|
-
- Parquet write failures automatically fall back to CSV
|
|
183
|
+
## Local data updates
|
|
163
184
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- If upstream data changes and you need a refresh, delete the relevant cache file(s) and rerun.
|
|
185
|
+
Backcaster reads the local CSV files for each command and does not use the old
|
|
186
|
+
FanGraphs season cache. To refresh the data, replace the CSVs with a complete
|
|
187
|
+
Lahman distribution from the same edition. Existing online caches are ignored.
|
|
168
188
|
|
|
169
189
|
---
|
|
170
190
|
|
|
@@ -172,7 +192,6 @@ Practical implications:
|
|
|
172
192
|
|
|
173
193
|
Runtime dependencies are intentionally minimal:
|
|
174
194
|
- `pandas` for tabular data processing and projection output
|
|
175
|
-
- `pybaseball` for MLB player/team seasonal stat retrieval and player ID lookup
|
|
176
195
|
|
|
177
196
|
Development dependencies (`--extra dev`) include:
|
|
178
197
|
- `pytest`, `pytest-cov`
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "backcaster"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
-
description = "Marcel-style MLB projection CLI
|
|
8
|
+
description = "Marcel-style MLB projection CLI using local Lahman CSV data"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
license-files = ["LICENSE"]
|
|
@@ -22,7 +22,6 @@ classifiers = [
|
|
|
22
22
|
requires-python = ">=3.13"
|
|
23
23
|
dependencies = [
|
|
24
24
|
"pandas>=2.0",
|
|
25
|
-
"pybaseball>=2.2",
|
|
26
25
|
]
|
|
27
26
|
|
|
28
27
|
[project.urls]
|
|
@@ -85,5 +84,5 @@ no_implicit_optional = true
|
|
|
85
84
|
check_untyped_defs = true
|
|
86
85
|
|
|
87
86
|
[[tool.mypy.overrides]]
|
|
88
|
-
module = ["pandas", "pandas.*"
|
|
87
|
+
module = ["pandas", "pandas.*"]
|
|
89
88
|
ignore_missing_imports = true
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
from backcaster.data import DataFetchError, PlayerLookupError
|
|
11
|
+
from backcaster.lahman import LahmanSource
|
|
12
|
+
from backcaster.marcel import ProjectionError
|
|
13
|
+
from backcaster.outputs import to_cli_table, to_csv, to_html
|
|
14
|
+
|
|
15
|
+
_FILE_RENDERERS = {"csv": to_csv, "html": to_html}
|
|
16
|
+
_OUTPUT_FORMAT_CHOICES = ("cli", *_FILE_RENDERERS.keys())
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _default_data_dir() -> str:
|
|
20
|
+
default = (
|
|
21
|
+
"C:/Baseball/lahman"
|
|
22
|
+
if sys.platform == "win32"
|
|
23
|
+
else str(Path.home() / "Baseball" / "lahman")
|
|
24
|
+
)
|
|
25
|
+
return os.environ.get("LAHMAN_DATA_DIR", default)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _render(df: pd.DataFrame, output_format: str, out: str | None) -> None:
|
|
29
|
+
if output_format == "cli":
|
|
30
|
+
print(to_cli_table(df))
|
|
31
|
+
elif output_format in _FILE_RENDERERS:
|
|
32
|
+
if not out:
|
|
33
|
+
raise ValueError(f"--out is required for {output_format} output")
|
|
34
|
+
_FILE_RENDERERS[output_format](df, out)
|
|
35
|
+
else:
|
|
36
|
+
raise ValueError(f"Unsupported format: {output_format}")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
40
|
+
p = argparse.ArgumentParser(prog="backcaster")
|
|
41
|
+
sub = p.add_subparsers(dest="command", required=True)
|
|
42
|
+
|
|
43
|
+
def add_common(sp: argparse.ArgumentParser) -> None:
|
|
44
|
+
sp.add_argument("--year", type=int, required=True)
|
|
45
|
+
sp.add_argument("--kind", choices=["batting", "pitching"], required=True)
|
|
46
|
+
sp.add_argument("--format", choices=_OUTPUT_FORMAT_CHOICES, default="cli")
|
|
47
|
+
sp.add_argument("--out")
|
|
48
|
+
sp.add_argument(
|
|
49
|
+
"--data-dir",
|
|
50
|
+
default=_default_data_dir(),
|
|
51
|
+
help="Lahman CSV directory (default: LAHMAN_DATA_DIR, C:/Baseball/lahman on Windows, or ~/Baseball/lahman)",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
pp = sub.add_parser("player")
|
|
55
|
+
add_common(pp)
|
|
56
|
+
pp.add_argument("--name", required=True)
|
|
57
|
+
|
|
58
|
+
tp = sub.add_parser("team")
|
|
59
|
+
add_common(tp)
|
|
60
|
+
tp.add_argument("--team", required=True)
|
|
61
|
+
|
|
62
|
+
bp = sub.add_parser("batch")
|
|
63
|
+
add_common(bp)
|
|
64
|
+
return p
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def main(argv: list[str] | None = None) -> int:
|
|
68
|
+
parser = build_parser()
|
|
69
|
+
args = parser.parse_args(argv)
|
|
70
|
+
try:
|
|
71
|
+
result = LahmanSource(args.data_dir).project(
|
|
72
|
+
args.command,
|
|
73
|
+
args.year,
|
|
74
|
+
args.kind,
|
|
75
|
+
name=getattr(args, "name", None),
|
|
76
|
+
team=getattr(args, "team", None),
|
|
77
|
+
)
|
|
78
|
+
_render(result, args.format, args.out)
|
|
79
|
+
return 0
|
|
80
|
+
except (DataFetchError, PlayerLookupError, ProjectionError, ValueError) as exc:
|
|
81
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
82
|
+
return 2
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
raise SystemExit(main())
|
|
@@ -21,7 +21,10 @@ class LahmanSource:
|
|
|
21
21
|
p for p in self.directory.glob("*") if p.name.casefold() == f"{name}.csv".casefold()
|
|
22
22
|
]
|
|
23
23
|
if len(paths) != 1:
|
|
24
|
-
raise DataFetchError(
|
|
24
|
+
raise DataFetchError(
|
|
25
|
+
f"Expected {name}.csv in Lahman directory '{self.directory}'. "
|
|
26
|
+
"Extract the Lahman CSVs there or select their directory with --data-dir."
|
|
27
|
+
)
|
|
25
28
|
try:
|
|
26
29
|
self.tables[name] = pd.read_csv(paths[0], encoding="utf-8-sig", low_memory=False)
|
|
27
30
|
except (OSError, ValueError) as exc:
|
|
@@ -128,7 +128,12 @@ def project_player(
|
|
|
128
128
|
|
|
129
129
|
pt_col = comps[0]
|
|
130
130
|
weighted_pt = float(weighted[pt_col])
|
|
131
|
-
|
|
131
|
+
# Regression uses weighted evidence, not the per-season average used for
|
|
132
|
+
# playing time. Averaging first would multiply regression strength by the
|
|
133
|
+
# sum of the season weights (12 for three seasons with weights 5/4/3).
|
|
134
|
+
evidence = weighted * sum(config.season_weights[: len(rows)])
|
|
135
|
+
evidence_pt = float(evidence[pt_col])
|
|
136
|
+
reliability = safe_divide(evidence_pt, evidence_pt + reg_pt)
|
|
132
137
|
|
|
133
138
|
if league_rates is None:
|
|
134
139
|
baseline_df = league_df if league_df is not None else prior_df
|
|
@@ -138,7 +143,7 @@ def project_player(
|
|
|
138
143
|
regressed[pt_col] = weighted_pt
|
|
139
144
|
for c in comps[1:]:
|
|
140
145
|
regressed_rate = safe_divide(
|
|
141
|
-
float(
|
|
146
|
+
float(evidence[c]) + league_rates[c] * reg_pt, evidence_pt + reg_pt
|
|
142
147
|
)
|
|
143
148
|
regressed[c] = regressed_rate * weighted_pt
|
|
144
149
|
|
|
@@ -18,7 +18,6 @@ class MarcelConfig:
|
|
|
18
18
|
regression_pa: float = 1200.0
|
|
19
19
|
regression_ip: float = 200.0
|
|
20
20
|
age_adjustment_fn: Callable[[float], float] = lambda age: 1.0 + (0.006 if age <= 29 else -0.003)
|
|
21
|
-
reliability_scale: float = 1200.0
|
|
22
21
|
default_pa_growth: float = 1.0
|
|
23
22
|
default_ip_growth: float = 1.0
|
|
24
23
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: backcaster
|
|
3
|
-
Version: 0.3.
|
|
4
|
-
Summary: Marcel-style MLB projection CLI
|
|
3
|
+
Version: 0.3.3
|
|
4
|
+
Summary: Marcel-style MLB projection CLI using local Lahman CSV data
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/jeffreywevans/backcaster
|
|
7
7
|
Project-URL: Repository, https://github.com/jeffreywevans/backcaster
|
|
@@ -18,7 +18,6 @@ Requires-Python: >=3.13
|
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: pandas>=2.0
|
|
21
|
-
Requires-Dist: pybaseball>=2.2
|
|
22
21
|
Provides-Extra: dev
|
|
23
22
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
24
23
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
@@ -30,7 +29,7 @@ Dynamic: license-file
|
|
|
30
29
|
|
|
31
30
|
# Backcaster
|
|
32
31
|
|
|
33
|
-
Backcaster is a Python CLI that produces **Marcel-style MLB projections** from the prior three seasons of data using
|
|
32
|
+
Backcaster is a Python CLI that produces **Marcel-style MLB projections** from the prior three seasons of data using local Lahman CSV files and `pandas`.
|
|
34
33
|
|
|
35
34
|
It supports:
|
|
36
35
|
- **Single player projections** (`player`)
|
|
@@ -44,7 +43,29 @@ It supports:
|
|
|
44
43
|
|
|
45
44
|
### Requirements
|
|
46
45
|
- Python **3.13+**
|
|
47
|
-
-
|
|
46
|
+
- An extracted Lahman CSV database covering the three prior seasons
|
|
47
|
+
- Internet access for package installation only; projections run offline
|
|
48
|
+
|
|
49
|
+
### Update an installed package
|
|
50
|
+
|
|
51
|
+
Upgrade to the latest release available on PyPI:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
python -m pip install --upgrade backcaster
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
To install a specific release, such as 0.3.3:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
python -m pip install --upgrade backcaster==0.3.3
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Run the command using the same Python environment where you run Backcaster.
|
|
64
|
+
If you use a virtual environment, activate it first. Check the installed version with:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
python -m pip show backcaster
|
|
68
|
+
```
|
|
48
69
|
|
|
49
70
|
### Install from source (recommended for contributors)
|
|
50
71
|
|
|
@@ -95,12 +116,23 @@ backcaster player --name "Mookie Betts" --year 2026 --kind batting
|
|
|
95
116
|
|
|
96
117
|
### Offline projections with Lahman CSVs
|
|
97
118
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
119
|
+
All projections use local Lahman CSVs. On Windows, the default directory is
|
|
120
|
+
`C:\Baseball\lahman`; on other systems it is `~/Baseball/lahman`.
|
|
121
|
+
Set the `LAHMAN_DATA_DIR` environment variable to change the default, or pass
|
|
122
|
+
`--data-dir` to override it for one command. No network requests or online
|
|
123
|
+
fallbacks are made. The directory must contain `People.csv`, `Teams.csv`, and
|
|
101
124
|
`Batting.csv` or `Pitching.csv` for the selected kind. Filenames are matched
|
|
102
125
|
without regard to case. The database is not bundled with Backcaster.
|
|
103
126
|
|
|
127
|
+
For the default Windows directory, no additional flag is needed:
|
|
128
|
+
|
|
129
|
+
```powershell
|
|
130
|
+
backcaster player --name "Mookie Betts" --year 2024 --kind batting
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
See [Lahman database notes](docs/LAHMAN.md) for the supplied 1871–2025 edition's
|
|
134
|
+
coverage, attribution, license, and historical-data caveats, with its original README.
|
|
135
|
+
|
|
104
136
|
```powershell
|
|
105
137
|
backcaster player --name "Mookie Betts" --year 2022 --kind batting --data-dir "C:\Baseball\lahman"
|
|
106
138
|
backcaster team --team LAN --year 2022 --kind batting --data-dir "C:\Baseball\lahman"
|
|
@@ -110,8 +142,8 @@ backcaster batch --year 2022 --kind pitching --data-dir "C:\Baseball\lahman" --f
|
|
|
110
142
|
Use Lahman's `teamID` values, such as `LAN` for the Dodgers (rather than the
|
|
111
143
|
FanGraphs abbreviation `LAD`). A projection year needs the preceding three seasons:
|
|
112
144
|
2022 requires 2019–2021. Missing seasons produce an error explaining which year
|
|
113
|
-
is unavailable.
|
|
114
|
-
|
|
145
|
+
is unavailable. If the directory or required files are missing, the command
|
|
146
|
+
reports the missing file and directory; it never attempts an online fetch.
|
|
115
147
|
|
|
116
148
|
Offline qualification uses a consistent modern rule across historical seasons:
|
|
117
149
|
at least **3.1 PA per game** for hitters and **one inning per game** for pitchers.
|
|
@@ -138,7 +170,7 @@ to the team in their latest stint for that season; this is not a current-roster
|
|
|
138
170
|
### 2) Team projection
|
|
139
171
|
|
|
140
172
|
```bash
|
|
141
|
-
backcaster team --team
|
|
173
|
+
backcaster team --team LAN --year 2026 --kind pitching
|
|
142
174
|
```
|
|
143
175
|
|
|
144
176
|
### 3) Batch projection (all players returned by source data)
|
|
@@ -151,7 +183,7 @@ backcaster batch --year 2026 --kind batting
|
|
|
151
183
|
|
|
152
184
|
```bash
|
|
153
185
|
backcaster player --name "Mookie Betts" --year 2026 --kind batting --format csv --out ./out/mookie_2026.csv
|
|
154
|
-
backcaster team --team
|
|
186
|
+
backcaster team --team LAN --year 2026 --kind pitching --format html --out ./out/lan_pitching_2026.html
|
|
155
187
|
```
|
|
156
188
|
|
|
157
189
|
> `--out` is required for `csv` and `html` formats.
|
|
@@ -177,24 +209,11 @@ A basic HTML table (no custom CSS) suitable for quick sharing or embedding.
|
|
|
177
209
|
|
|
178
210
|
---
|
|
179
211
|
|
|
180
|
-
##
|
|
181
|
-
|
|
182
|
-
Backcaster caches season stat pulls under:
|
|
183
|
-
|
|
184
|
-
```text
|
|
185
|
-
~/.cache/backcaster/
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Cache details:
|
|
189
|
-
- Key pattern: `<kind>_<year>.parquet` (preferred) or `<kind>_<year>.csv` (fallback)
|
|
190
|
-
- Read order: Parquet first, then CSV
|
|
191
|
-
- Write behavior: atomic temp-file write + rename to reduce corruption risk
|
|
192
|
-
- Parquet write failures automatically fall back to CSV
|
|
212
|
+
## Local data updates
|
|
193
213
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
- If upstream data changes and you need a refresh, delete the relevant cache file(s) and rerun.
|
|
214
|
+
Backcaster reads the local CSV files for each command and does not use the old
|
|
215
|
+
FanGraphs season cache. To refresh the data, replace the CSVs with a complete
|
|
216
|
+
Lahman distribution from the same edition. Existing online caches are ignored.
|
|
198
217
|
|
|
199
218
|
---
|
|
200
219
|
|
|
@@ -202,7 +221,6 @@ Practical implications:
|
|
|
202
221
|
|
|
203
222
|
Runtime dependencies are intentionally minimal:
|
|
204
223
|
- `pandas` for tabular data processing and projection output
|
|
205
|
-
- `pybaseball` for MLB player/team seasonal stat retrieval and player ID lookup
|
|
206
224
|
|
|
207
225
|
Development dependencies (`--extra dev`) include:
|
|
208
226
|
- `pytest`, `pytest-cov`
|
|
@@ -16,10 +16,7 @@ src/backcaster.egg-info/entry_points.txt
|
|
|
16
16
|
src/backcaster.egg-info/requires.txt
|
|
17
17
|
src/backcaster.egg-info/top_level.txt
|
|
18
18
|
tests/test_cli.py
|
|
19
|
-
tests/test_cli_player_lookup.py
|
|
20
|
-
tests/test_data.py
|
|
21
19
|
tests/test_lahman.py
|
|
22
20
|
tests/test_marcel_math.py
|
|
23
21
|
tests/test_normalize.py
|
|
24
|
-
tests/test_outputs.py
|
|
25
|
-
tests/test_player_lookup.py
|
|
22
|
+
tests/test_outputs.py
|