backcaster 0.3.2__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.2/src/backcaster.egg-info → backcaster-0.3.3}/PKG-INFO +26 -32
- {backcaster-0.3.2 → backcaster-0.3.3}/README.md +24 -29
- {backcaster-0.3.2 → backcaster-0.3.3}/pyproject.toml +2 -3
- {backcaster-0.3.2 → 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.2 → backcaster-0.3.3}/src/backcaster/lahman.py +4 -1
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster/marcel.py +7 -2
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster/schemas.py +0 -1
- {backcaster-0.3.2 → backcaster-0.3.3/src/backcaster.egg-info}/PKG-INFO +26 -32
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster.egg-info/SOURCES.txt +1 -4
- {backcaster-0.3.2 → 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.2 → backcaster-0.3.3}/tests/test_lahman.py +27 -2
- {backcaster-0.3.2 → backcaster-0.3.3}/tests/test_marcel_math.py +49 -0
- backcaster-0.3.2/src/backcaster/cli.py +0 -176
- backcaster-0.3.2/src/backcaster/data.py +0 -246
- backcaster-0.3.2/tests/test_cli.py +0 -259
- backcaster-0.3.2/tests/test_cli_player_lookup.py +0 -60
- backcaster-0.3.2/tests/test_data.py +0 -412
- backcaster-0.3.2/tests/test_player_lookup.py +0 -89
- {backcaster-0.3.2 → backcaster-0.3.3}/LICENSE +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/setup.cfg +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster/normalize.py +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster/outputs.py +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster.egg-info/dependency_links.txt +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster.egg-info/entry_points.txt +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/src/backcaster.egg-info/top_level.txt +0 -0
- {backcaster-0.3.2 → backcaster-0.3.3}/tests/test_normalize.py +0 -0
- {backcaster-0.3.2 → 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,8 @@ 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
48
|
|
|
49
49
|
### Update an installed package
|
|
50
50
|
|
|
@@ -54,10 +54,10 @@ Upgrade to the latest release available on PyPI:
|
|
|
54
54
|
python -m pip install --upgrade backcaster
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
To install a specific release, such as 0.3.
|
|
57
|
+
To install a specific release, such as 0.3.3:
|
|
58
58
|
|
|
59
59
|
```powershell
|
|
60
|
-
python -m pip install --upgrade backcaster==0.3.
|
|
60
|
+
python -m pip install --upgrade backcaster==0.3.3
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Run the command using the same Python environment where you run Backcaster.
|
|
@@ -116,12 +116,20 @@ backcaster player --name "Mookie Betts" --year 2026 --kind batting
|
|
|
116
116
|
|
|
117
117
|
### Offline projections with Lahman CSVs
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
122
124
|
`Batting.csv` or `Pitching.csv` for the selected kind. Filenames are matched
|
|
123
125
|
without regard to case. The database is not bundled with Backcaster.
|
|
124
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
|
+
|
|
125
133
|
See [Lahman database notes](docs/LAHMAN.md) for the supplied 1871–2025 edition's
|
|
126
134
|
coverage, attribution, license, and historical-data caveats, with its original README.
|
|
127
135
|
|
|
@@ -134,8 +142,8 @@ backcaster batch --year 2022 --kind pitching --data-dir "C:\Baseball\lahman" --f
|
|
|
134
142
|
Use Lahman's `teamID` values, such as `LAN` for the Dodgers (rather than the
|
|
135
143
|
FanGraphs abbreviation `LAD`). A projection year needs the preceding three seasons:
|
|
136
144
|
2022 requires 2019–2021. Missing seasons produce an error explaining which year
|
|
137
|
-
is unavailable.
|
|
138
|
-
|
|
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.
|
|
139
147
|
|
|
140
148
|
Offline qualification uses a consistent modern rule across historical seasons:
|
|
141
149
|
at least **3.1 PA per game** for hitters and **one inning per game** for pitchers.
|
|
@@ -162,7 +170,7 @@ to the team in their latest stint for that season; this is not a current-roster
|
|
|
162
170
|
### 2) Team projection
|
|
163
171
|
|
|
164
172
|
```bash
|
|
165
|
-
backcaster team --team
|
|
173
|
+
backcaster team --team LAN --year 2026 --kind pitching
|
|
166
174
|
```
|
|
167
175
|
|
|
168
176
|
### 3) Batch projection (all players returned by source data)
|
|
@@ -175,7 +183,7 @@ backcaster batch --year 2026 --kind batting
|
|
|
175
183
|
|
|
176
184
|
```bash
|
|
177
185
|
backcaster player --name "Mookie Betts" --year 2026 --kind batting --format csv --out ./out/mookie_2026.csv
|
|
178
|
-
backcaster team --team
|
|
186
|
+
backcaster team --team LAN --year 2026 --kind pitching --format html --out ./out/lan_pitching_2026.html
|
|
179
187
|
```
|
|
180
188
|
|
|
181
189
|
> `--out` is required for `csv` and `html` formats.
|
|
@@ -201,24 +209,11 @@ A basic HTML table (no custom CSS) suitable for quick sharing or embedding.
|
|
|
201
209
|
|
|
202
210
|
---
|
|
203
211
|
|
|
204
|
-
##
|
|
205
|
-
|
|
206
|
-
Backcaster caches season stat pulls under:
|
|
207
|
-
|
|
208
|
-
```text
|
|
209
|
-
~/.cache/backcaster/
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
Cache details:
|
|
213
|
-
- Key pattern: `<kind>_<year>.parquet` (preferred) or `<kind>_<year>.csv` (fallback)
|
|
214
|
-
- Read order: Parquet first, then CSV
|
|
215
|
-
- Write behavior: atomic temp-file write + rename to reduce corruption risk
|
|
216
|
-
- Parquet write failures automatically fall back to CSV
|
|
212
|
+
## Local data updates
|
|
217
213
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- 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.
|
|
222
217
|
|
|
223
218
|
---
|
|
224
219
|
|
|
@@ -226,7 +221,6 @@ Practical implications:
|
|
|
226
221
|
|
|
227
222
|
Runtime dependencies are intentionally minimal:
|
|
228
223
|
- `pandas` for tabular data processing and projection output
|
|
229
|
-
- `pybaseball` for MLB player/team seasonal stat retrieval and player ID lookup
|
|
230
224
|
|
|
231
225
|
Development dependencies (`--extra dev`) include:
|
|
232
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,8 @@ 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
|
|
18
19
|
|
|
19
20
|
### Update an installed package
|
|
20
21
|
|
|
@@ -24,10 +25,10 @@ Upgrade to the latest release available on PyPI:
|
|
|
24
25
|
python -m pip install --upgrade backcaster
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
To install a specific release, such as 0.3.
|
|
28
|
+
To install a specific release, such as 0.3.3:
|
|
28
29
|
|
|
29
30
|
```powershell
|
|
30
|
-
python -m pip install --upgrade backcaster==0.3.
|
|
31
|
+
python -m pip install --upgrade backcaster==0.3.3
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
Run the command using the same Python environment where you run Backcaster.
|
|
@@ -86,12 +87,20 @@ backcaster player --name "Mookie Betts" --year 2026 --kind batting
|
|
|
86
87
|
|
|
87
88
|
### Offline projections with Lahman CSVs
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
92
95
|
`Batting.csv` or `Pitching.csv` for the selected kind. Filenames are matched
|
|
93
96
|
without regard to case. The database is not bundled with Backcaster.
|
|
94
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
|
+
|
|
95
104
|
See [Lahman database notes](docs/LAHMAN.md) for the supplied 1871–2025 edition's
|
|
96
105
|
coverage, attribution, license, and historical-data caveats, with its original README.
|
|
97
106
|
|
|
@@ -104,8 +113,8 @@ backcaster batch --year 2022 --kind pitching --data-dir "C:\Baseball\lahman" --f
|
|
|
104
113
|
Use Lahman's `teamID` values, such as `LAN` for the Dodgers (rather than the
|
|
105
114
|
FanGraphs abbreviation `LAD`). A projection year needs the preceding three seasons:
|
|
106
115
|
2022 requires 2019–2021. Missing seasons produce an error explaining which year
|
|
107
|
-
is unavailable.
|
|
108
|
-
|
|
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.
|
|
109
118
|
|
|
110
119
|
Offline qualification uses a consistent modern rule across historical seasons:
|
|
111
120
|
at least **3.1 PA per game** for hitters and **one inning per game** for pitchers.
|
|
@@ -132,7 +141,7 @@ to the team in their latest stint for that season; this is not a current-roster
|
|
|
132
141
|
### 2) Team projection
|
|
133
142
|
|
|
134
143
|
```bash
|
|
135
|
-
backcaster team --team
|
|
144
|
+
backcaster team --team LAN --year 2026 --kind pitching
|
|
136
145
|
```
|
|
137
146
|
|
|
138
147
|
### 3) Batch projection (all players returned by source data)
|
|
@@ -145,7 +154,7 @@ backcaster batch --year 2026 --kind batting
|
|
|
145
154
|
|
|
146
155
|
```bash
|
|
147
156
|
backcaster player --name "Mookie Betts" --year 2026 --kind batting --format csv --out ./out/mookie_2026.csv
|
|
148
|
-
backcaster team --team
|
|
157
|
+
backcaster team --team LAN --year 2026 --kind pitching --format html --out ./out/lan_pitching_2026.html
|
|
149
158
|
```
|
|
150
159
|
|
|
151
160
|
> `--out` is required for `csv` and `html` formats.
|
|
@@ -171,24 +180,11 @@ A basic HTML table (no custom CSS) suitable for quick sharing or embedding.
|
|
|
171
180
|
|
|
172
181
|
---
|
|
173
182
|
|
|
174
|
-
##
|
|
175
|
-
|
|
176
|
-
Backcaster caches season stat pulls under:
|
|
177
|
-
|
|
178
|
-
```text
|
|
179
|
-
~/.cache/backcaster/
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
Cache details:
|
|
183
|
-
- Key pattern: `<kind>_<year>.parquet` (preferred) or `<kind>_<year>.csv` (fallback)
|
|
184
|
-
- Read order: Parquet first, then CSV
|
|
185
|
-
- Write behavior: atomic temp-file write + rename to reduce corruption risk
|
|
186
|
-
- Parquet write failures automatically fall back to CSV
|
|
183
|
+
## Local data updates
|
|
187
184
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
- 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.
|
|
192
188
|
|
|
193
189
|
---
|
|
194
190
|
|
|
@@ -196,7 +192,6 @@ Practical implications:
|
|
|
196
192
|
|
|
197
193
|
Runtime dependencies are intentionally minimal:
|
|
198
194
|
- `pandas` for tabular data processing and projection output
|
|
199
|
-
- `pybaseball` for MLB player/team seasonal stat retrieval and player ID lookup
|
|
200
195
|
|
|
201
196
|
Development dependencies (`--extra dev`) include:
|
|
202
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,8 @@ 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
48
|
|
|
49
49
|
### Update an installed package
|
|
50
50
|
|
|
@@ -54,10 +54,10 @@ Upgrade to the latest release available on PyPI:
|
|
|
54
54
|
python -m pip install --upgrade backcaster
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
To install a specific release, such as 0.3.
|
|
57
|
+
To install a specific release, such as 0.3.3:
|
|
58
58
|
|
|
59
59
|
```powershell
|
|
60
|
-
python -m pip install --upgrade backcaster==0.3.
|
|
60
|
+
python -m pip install --upgrade backcaster==0.3.3
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Run the command using the same Python environment where you run Backcaster.
|
|
@@ -116,12 +116,20 @@ backcaster player --name "Mookie Betts" --year 2026 --kind batting
|
|
|
116
116
|
|
|
117
117
|
### Offline projections with Lahman CSVs
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
122
124
|
`Batting.csv` or `Pitching.csv` for the selected kind. Filenames are matched
|
|
123
125
|
without regard to case. The database is not bundled with Backcaster.
|
|
124
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
|
+
|
|
125
133
|
See [Lahman database notes](docs/LAHMAN.md) for the supplied 1871–2025 edition's
|
|
126
134
|
coverage, attribution, license, and historical-data caveats, with its original README.
|
|
127
135
|
|
|
@@ -134,8 +142,8 @@ backcaster batch --year 2022 --kind pitching --data-dir "C:\Baseball\lahman" --f
|
|
|
134
142
|
Use Lahman's `teamID` values, such as `LAN` for the Dodgers (rather than the
|
|
135
143
|
FanGraphs abbreviation `LAD`). A projection year needs the preceding three seasons:
|
|
136
144
|
2022 requires 2019–2021. Missing seasons produce an error explaining which year
|
|
137
|
-
is unavailable.
|
|
138
|
-
|
|
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.
|
|
139
147
|
|
|
140
148
|
Offline qualification uses a consistent modern rule across historical seasons:
|
|
141
149
|
at least **3.1 PA per game** for hitters and **one inning per game** for pitchers.
|
|
@@ -162,7 +170,7 @@ to the team in their latest stint for that season; this is not a current-roster
|
|
|
162
170
|
### 2) Team projection
|
|
163
171
|
|
|
164
172
|
```bash
|
|
165
|
-
backcaster team --team
|
|
173
|
+
backcaster team --team LAN --year 2026 --kind pitching
|
|
166
174
|
```
|
|
167
175
|
|
|
168
176
|
### 3) Batch projection (all players returned by source data)
|
|
@@ -175,7 +183,7 @@ backcaster batch --year 2026 --kind batting
|
|
|
175
183
|
|
|
176
184
|
```bash
|
|
177
185
|
backcaster player --name "Mookie Betts" --year 2026 --kind batting --format csv --out ./out/mookie_2026.csv
|
|
178
|
-
backcaster team --team
|
|
186
|
+
backcaster team --team LAN --year 2026 --kind pitching --format html --out ./out/lan_pitching_2026.html
|
|
179
187
|
```
|
|
180
188
|
|
|
181
189
|
> `--out` is required for `csv` and `html` formats.
|
|
@@ -201,24 +209,11 @@ A basic HTML table (no custom CSS) suitable for quick sharing or embedding.
|
|
|
201
209
|
|
|
202
210
|
---
|
|
203
211
|
|
|
204
|
-
##
|
|
205
|
-
|
|
206
|
-
Backcaster caches season stat pulls under:
|
|
207
|
-
|
|
208
|
-
```text
|
|
209
|
-
~/.cache/backcaster/
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
Cache details:
|
|
213
|
-
- Key pattern: `<kind>_<year>.parquet` (preferred) or `<kind>_<year>.csv` (fallback)
|
|
214
|
-
- Read order: Parquet first, then CSV
|
|
215
|
-
- Write behavior: atomic temp-file write + rename to reduce corruption risk
|
|
216
|
-
- Parquet write failures automatically fall back to CSV
|
|
212
|
+
## Local data updates
|
|
217
213
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- 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.
|
|
222
217
|
|
|
223
218
|
---
|
|
224
219
|
|
|
@@ -226,7 +221,6 @@ Practical implications:
|
|
|
226
221
|
|
|
227
222
|
Runtime dependencies are intentionally minimal:
|
|
228
223
|
- `pandas` for tabular data processing and projection output
|
|
229
|
-
- `pybaseball` for MLB player/team seasonal stat retrieval and player ID lookup
|
|
230
224
|
|
|
231
225
|
Development dependencies (`--extra dev`) include:
|
|
232
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
|