pokeductor 0.7.0

A terminal Pokedex and evolution analyzer with sprite rendering, offline type and party analysis, and an on-disk cache for offline use
#!/usr/bin/env python3
"""Regenerates src/base_stats.tsv, the built-in base stat table.

Stat terms in the search box (`spe>=110`, `bst>600`) and the stat sort orders
need every entry's base stats, which PokeAPI only serves one `/pokemon/{name}`
request at a time. Rather than fetch thirteen hundred records for a keypress,
the binary carries a table, generated here from the CSV files PokeAPI itself
is built from. Names are PokeAPI's identifiers, the same ones the master list
uses, alternate forms included.

Run it after a new generation lands in PokeAPI:

    python3 scripts/base-stats.py > src/base_stats.tsv

Standard library only.
"""

import csv
import io
import sys
import urllib.request

SOURCE = "https://raw.githubusercontent.com/PokeAPI/pokeapi/master/data/v2/csv"

# PokeAPI's stat ids, in the order the table's columns use. 7 and 8 are the
# battle-only accuracy and evasion stages, which no species has a base for.
STAT_IDS = [1, 2, 3, 4, 5, 6]


def fetch(name):
    with urllib.request.urlopen(f"{SOURCE}/{name}") as response:
        return list(csv.DictReader(io.TextIOWrapper(response, encoding="utf-8")))


def main():
    names = {int(row["id"]): row["identifier"] for row in fetch("pokemon.csv")}
    stats = {}
    for row in fetch("pokemon_stats.csv"):
        stats.setdefault(int(row["pokemon_id"]), {})[int(row["stat_id"])] = int(
            row["base_stat"]
        )

    out = sys.stdout
    out.write("# Generated by scripts/base-stats.py from PokeAPI's CSV data.\n")
    out.write("# name\thp\tatk\tdef\tspa\tspd\tspe\n")
    for pokemon_id in sorted(names):
        row = stats.get(pokemon_id, {})
        if any(stat not in row for stat in STAT_IDS):
            sys.exit(f"{names[pokemon_id]} is missing a base stat")
        values = "\t".join(str(row[stat]) for stat in STAT_IDS)
        out.write(f"{names[pokemon_id]}\t{values}\n")


if __name__ == "__main__":
    main()