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.
Files changed (30) hide show
  1. {backcaster-0.3.1/src/backcaster.egg-info → backcaster-0.3.3}/PKG-INFO +48 -30
  2. {backcaster-0.3.1 → backcaster-0.3.3}/README.md +46 -27
  3. {backcaster-0.3.1 → backcaster-0.3.3}/pyproject.toml +2 -3
  4. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/__init__.py +1 -1
  5. backcaster-0.3.3/src/backcaster/cli.py +86 -0
  6. backcaster-0.3.3/src/backcaster/data.py +9 -0
  7. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/lahman.py +4 -1
  8. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/marcel.py +7 -2
  9. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/schemas.py +0 -1
  10. {backcaster-0.3.1 → backcaster-0.3.3/src/backcaster.egg-info}/PKG-INFO +48 -30
  11. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/SOURCES.txt +1 -4
  12. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/requires.txt +0 -1
  13. backcaster-0.3.3/tests/test_cli.py +102 -0
  14. {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_lahman.py +27 -2
  15. {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_marcel_math.py +49 -0
  16. backcaster-0.3.1/src/backcaster/cli.py +0 -176
  17. backcaster-0.3.1/src/backcaster/data.py +0 -246
  18. backcaster-0.3.1/tests/test_cli.py +0 -259
  19. backcaster-0.3.1/tests/test_cli_player_lookup.py +0 -60
  20. backcaster-0.3.1/tests/test_data.py +0 -412
  21. backcaster-0.3.1/tests/test_player_lookup.py +0 -89
  22. {backcaster-0.3.1 → backcaster-0.3.3}/LICENSE +0 -0
  23. {backcaster-0.3.1 → backcaster-0.3.3}/setup.cfg +0 -0
  24. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/normalize.py +0 -0
  25. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster/outputs.py +0 -0
  26. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/dependency_links.txt +0 -0
  27. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/entry_points.txt +0 -0
  28. {backcaster-0.3.1 → backcaster-0.3.3}/src/backcaster.egg-info/top_level.txt +0 -0
  29. {backcaster-0.3.1 → backcaster-0.3.3}/tests/test_normalize.py +0 -0
  30. {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.1
4
- Summary: Marcel-style MLB projection CLI built on pybaseball
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 [`pybaseball`](https://github.com/jldbc/pybaseball) and `pandas`.
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
- - Internet access for first-time stat fetches (data is cached locally afterward)
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
- Extract your Lahman CSV distribution into a local directory. Pass `--data-dir`
99
- to use it without any network requests, player-register downloads, or FanGraphs
100
- cache reads. The directory must contain `People.csv`, `Teams.csv`, and
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. Without `--data-dir`, the existing pybaseball source is used;
114
- FanGraphs may reject its automated requests with HTTP 403.
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 LAD --year 2026 --kind pitching
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 LAD --year 2026 --kind pitching --format html --out ./out/lad_pitching_2026.html
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
- ## Cache behavior
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
- Practical implications:
195
- - First run for a season may be slower (network fetch).
196
- - Re-runs are typically faster (local cache hit).
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 [`pybaseball`](https://github.com/jldbc/pybaseball) and `pandas`.
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
- - Internet access for first-time stat fetches (data is cached locally afterward)
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
- Extract your Lahman CSV distribution into a local directory. Pass `--data-dir`
69
- to use it without any network requests, player-register downloads, or FanGraphs
70
- cache reads. The directory must contain `People.csv`, `Teams.csv`, and
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. Without `--data-dir`, the existing pybaseball source is used;
84
- FanGraphs may reject its automated requests with HTTP 403.
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 LAD --year 2026 --kind pitching
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 LAD --year 2026 --kind pitching --format html --out ./out/lad_pitching_2026.html
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
- ## Cache behavior
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
- Practical implications:
165
- - First run for a season may be slower (network fetch).
166
- - Re-runs are typically faster (local cache hit).
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 built on pybaseball"
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.*", "pybaseball", "pybaseball.*"]
87
+ module = ["pandas", "pandas.*"]
89
88
  ignore_missing_imports = true
@@ -1,4 +1,4 @@
1
1
  """backcaster package."""
2
2
 
3
3
  __all__ = ["__version__"]
4
- __version__ = "0.3.1"
4
+ __version__ = "0.3.3"
@@ -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())
@@ -0,0 +1,9 @@
1
+ """Errors reported when local source data cannot be loaded or resolved."""
2
+
3
+
4
+ class DataFetchError(RuntimeError):
5
+ pass
6
+
7
+
8
+ class PlayerLookupError(RuntimeError):
9
+ pass
@@ -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(f"Expected {name}.csv in Lahman directory '{self.directory}'.")
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
- reliability = min(1.0, safe_divide(weighted_pt, config.reliability_scale))
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(weighted[c]) + league_rates[c] * reg_pt, weighted_pt + reg_pt
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.1
4
- Summary: Marcel-style MLB projection CLI built on pybaseball
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 [`pybaseball`](https://github.com/jldbc/pybaseball) and `pandas`.
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
- - Internet access for first-time stat fetches (data is cached locally afterward)
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
- Extract your Lahman CSV distribution into a local directory. Pass `--data-dir`
99
- to use it without any network requests, player-register downloads, or FanGraphs
100
- cache reads. The directory must contain `People.csv`, `Teams.csv`, and
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. Without `--data-dir`, the existing pybaseball source is used;
114
- FanGraphs may reject its automated requests with HTTP 403.
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 LAD --year 2026 --kind pitching
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 LAD --year 2026 --kind pitching --format html --out ./out/lad_pitching_2026.html
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
- ## Cache behavior
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
- Practical implications:
195
- - First run for a season may be slower (network fetch).
196
- - Re-runs are typically faster (local cache hit).
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
@@ -1,5 +1,4 @@
1
1
  pandas>=2.0
2
- pybaseball>=2.2
3
2
 
4
3
  [dev]
5
4
  pytest>=8.0