Skip to content

Commit bed77bb

Browse files
committed
README: full restructure, uv install one-liner, Build step in new-year flow
User restructured 'Adding a new election year' into a tight numbered list with 'Details for Nerds' below the fold. Then on follow-up: - Added a uv install one-liner at the top of Quick start (since the rest of the README assumes uv is installed) - Added a Build step (step 3) in the new-year flow between Download and Commit, so the user actually generates the CSVs before being told to commit them - Dropped the redundant 'One-Shot Command for the Impatient' section below — step 3 now covers it
1 parent bdc422b commit bed77bb

1 file changed

Lines changed: 48 additions & 30 deletions

File tree

README.md

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ read-only history.
1919

2020
### Quick start: re-generate an existing year's CSVs
2121

22+
The framework runs on Python 3 via [uv](https://docs.astral.sh/uv/).
23+
If you don't have `uv` yet, install it with one of:
24+
25+
```bash
26+
curl -LsSf https://astral.sh/uv/install.sh | sh # Mac or Linux
27+
brew install uv # Mac with Homebrew
28+
pip install uv # any platform with Python + pip
29+
```
30+
2231
All `uv` commands below run in a terminal, from the project root
2332
(the directory that contains this `README.md`).
2433

@@ -44,7 +53,7 @@ the build's pre-flight scan, not at argument-parse time.
4453
### Adding a new election year
4554

4655
NH SoS publishes new election workbooks roughly six weeks after the
47-
election. To add a year (say 2026), three commands total:
56+
election. To add a year (say 2026):
4857

4958
1. **Scaffold the year:**
5059

@@ -65,47 +74,32 @@ election. To add a year (say 2026), three commands total:
6574
[scripts/fetch-raw.md](scripts/fetch-raw.md) for the per-office
6675
download details.
6776

68-
**Drop the downloaded files into `raw/2026/general/`.** You don't
69-
have to rename them — the framework recognizes both canonical
70-
short-form names and the longer names the SoS publishes
71-
(`2026-ge-house-belknap_1.xls` and `house-belknap.xls` both work).
72-
The canonical short forms for reference:
73-
74-
| Office | Canonical filename(s) |
75-
| --- | --- |
76-
| President | `president.xls[x]` |
77-
| Governor | `governor.xls[x]` |
78-
| US Senate | `us-senate.xls[x]` |
79-
| Congressional | `congressional-1.xls[x]`, `congressional-2.xls[x]` |
80-
| Executive Council | `executive-council.xls[x]` |
81-
| State Senate | `state-senate.xls[x]` |
82-
| State Representative | `house-belknap.xls[x]`, `house-carroll.xls[x]`, … (one per NH county) |
83-
84-
The build command's pre-flight scan tells you which files matched
85-
which office (and which weren't recognized), so any naming mistake
86-
is surfaced before parsing starts. Offices that aren't on the
87-
year's ballot (e.g. no Presidential in midterms) just show up as
88-
`⚠️ skipped` in the summary — not an error.
77+
**Drop the downloaded files into `raw/2026/general/`.** No need to
78+
rename them — the framework recognizes SoS-shaped filenames as well
79+
as canonical short forms.
8980

90-
3. **Build everything in one shot:**
81+
3. **Build the CSVs:**
9182

9283
```bash
9384
uv run python -m oe_nh.cli --year 2026
9485
```
9586

96-
You'll get a pre-flight scan ("found these files, will build these
97-
offices, ignoring these unknowns"), per-office build lines, and a
98-
trailing summary with ✅/⚠️/❌ status and total row counts. CSVs
99-
land under `2026/`. Anything missing or surprising is reported
100-
once, in the summary — no need to scroll through logs.
87+
You'll get a pre-flight scan, per-office build lines, and a trailing
88+
summary with ✅/⚠️/❌ status and row counts. CSVs land under
89+
`2026/`. Anything missing or surprising is reported once, in the
90+
summary — see "Details for Nerds" below for what `⚠️` and `` mean.
10191

102-
4. **Commit** the new raw files (`raw/2026/general/*.xls*`) AND the
103-
generated CSVs (`2026/*.csv`) AND `raw/2026/.dates.json`. All three
92+
4. **Commit** the new raw files (`raw/2026/general/*.xls*`), the
93+
generated CSVs (`2026/*.csv`), and `raw/2026/.dates.json`. All three
10494
belong in version control: raw files so the build is reproducible,
10595
CSVs because they're the published product OpenElections consumes,
10696
and the dates file because it's what tells the framework this year
10797
is registered.
10898

99+
---------
100+
101+
## Details for Nerds
102+
109103
### Output conventions
110104

111105
- **Schema** is `county,precinct,office,district,party,candidate,votes` — one row per (precinct, candidate) pair.
@@ -134,3 +128,27 @@ Parser + Config dataclass (`CongressionalParser`,
134128
`parse_workbook(path, config)` factory dispatches on config type. Add a
135129
new shape by writing a new Parser + Config and adding a branch to the
136130
factory plus an entry to `discovery._DISPATCH`.
131+
132+
### File Naming Details
133+
134+
**Drop the downloaded files into `raw/2026/general/`.** You don't
135+
have to rename them — the framework recognizes both canonical
136+
short-form names and the longer names the SoS publishes
137+
(`2026-ge-house-belknap_1.xls` and `house-belknap.xls` both work).
138+
The canonical short forms for reference:
139+
140+
| Office | Canonical filename(s) |
141+
| --- | --- |
142+
| President | `president.xls[x]` |
143+
| Governor | `governor.xls[x]` |
144+
| US Senate | `us-senate.xls[x]` |
145+
| Congressional | `congressional-1.xls[x]`, `congressional-2.xls[x]` |
146+
| Executive Council | `executive-council.xls[x]` |
147+
| State Senate | `state-senate.xls[x]` |
148+
| State Representative | `house-belknap.xls[x]`, `house-carroll.xls[x]`, … (one per NH county) |
149+
150+
The build command's pre-flight scan tells you which files matched
151+
which office (and which weren't recognized), so any naming mistake
152+
is surfaced before parsing starts. Offices that aren't on the
153+
year's ballot (e.g. no Presidential in midterms) just show up as
154+
`⚠️ skipped` in the summary — not an error.

0 commit comments

Comments
 (0)