58 lines
3.6 KiB
Python
58 lines
3.6 KiB
Python
"""Regenerate fictional examples. Never use these as real election data."""
|
|
import json
|
|
import pathlib
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parents[1] / "data" / "demo"
|
|
SOURCE = {"name": "Fictional scoring fixtures", "url": "fixture:product-fpol/demo", "retrieved_at": "2026-10-01T00:00:00Z"}
|
|
|
|
def save(name, document):
|
|
(ROOT / name).write_text(json.dumps(document, indent=2) + "\n")
|
|
|
|
def header(kind, identity, label, date):
|
|
return {"schema_version": 1, "id": identity, "kind": kind, "mode": "demo", "label": label,
|
|
"as_of": date, "source": SOURCE.copy()}
|
|
|
|
def main():
|
|
ROOT.mkdir(parents=True, exist_ok=True)
|
|
catalog = header("catalog", "demo-2026", "Fictional league • 144 candidates", "2026-10-01T00:00:00Z")
|
|
catalog.update(complete=True, races=[], candidates=[])
|
|
ratings = header("ratings", "demo-ratings-v1", "Frozen fictional ratings", "2026-10-02T00:00:00Z")
|
|
ratings.update(catalog_id=catalog["id"], entries=[])
|
|
states = ["AZ", "GA", "MI", "PA", "NC", "TX", "OH", "WI", "NV", "FL", "ME", "CO"]
|
|
names = ["Avery", "Blair", "Casey", "Drew"]
|
|
roster = []
|
|
for office in ("house", "senate", "governor"):
|
|
for index, state in enumerate(states, start=1):
|
|
race_id = f"demo-{office}-{index:02}"
|
|
catalog["races"].append({"id": race_id, "office": office, "state": state, "round": "general",
|
|
"name": f"Fictional {state} {office.title()} race {index}"})
|
|
ratings["entries"].append({"race_id": race_id, "rating": ["safe", "likely", "lean", "toss_up"][(index - 1) % 4]})
|
|
for number, affiliation in enumerate(("democrat", "republican", "other", "other")):
|
|
identity = f"{race_id}-{number + 1}"
|
|
catalog["candidates"].append({"id": identity, "race_id": race_id, "name": f"{names[number]} {office.title()} {index:02}",
|
|
"affiliation": affiliation, "qualified": True, "ballot_lines": [affiliation.title()],
|
|
"provider_ids": {"fictional": identity}, "source": SOURCE.copy()})
|
|
for slot, race_number, candidate_number in (("democrat", 4, 1), ("republican", 1, 2), ("other", 2, 3), ("flex", 3, 4)):
|
|
roster.append({"slot": f"{office}:{slot}", "candidate_id": f"demo-{office}-{race_number:02}-{candidate_number}"})
|
|
save("catalog.json", catalog)
|
|
save("ratings.json", ratings)
|
|
for step, label in enumerate(("No votes yet", "Early reporting", "Lead changes", "Races called", "Corrected totals and call")):
|
|
result = header("results", f"demo-results-{step}", f"Synthetic replay {step + 1}: {label}", f"2026-11-04T0{step}:00:00Z")
|
|
result.update(catalog_id=catalog["id"], entries=[])
|
|
for index, race in enumerate(catalog["races"]):
|
|
distribution = ([800, 150, 30, 20] if index % 4 == 0 else [600, 300, 70, 30] if index % 4 == 1 else
|
|
[540, 420, 25, 15] if index % 4 == 2 else [510, 490, 0, 0])
|
|
if index % 4 == 3 and step in (2, 4):
|
|
distribution = [490, 510, 0, 0]
|
|
distribution = [0, 0, 0, 0] if step == 0 else distribution
|
|
winner = None if step < 3 else f"{race['id']}-{1 if distribution[0] > distribution[1] else 2}"
|
|
result["entries"].append({"race_id": race["id"], "round": "general", "status": "called" if step >= 3 else "reporting",
|
|
"total_votes": sum(distribution), "winner_id": winner,
|
|
"votes": [{"candidate_id": f"{race['id']}-{number + 1}", "votes": count} for number, count in enumerate(distribution)]})
|
|
save(f"results-{step}.json", result)
|
|
save("preview.json", {"catalog_id": catalog["id"], "ratings_id": ratings["id"], "results_id": "demo-results-3", "roster": roster})
|
|
save("capacity.json", {"catalog_id": catalog["id"], "players": 12})
|
|
|
|
if __name__ == "__main__":
|
|
main()
|