Files
nuzlocke-tracker/backend/scripts/fetch_moves_abilities.py
Julian Tabel c9d42b091f
All checks were successful
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 29s
Daedalus and Talos integration test
2026-03-20 16:31:19 +01:00

188 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""Fetch moves and abilities from PokeAPI and save as seed data JSON files.
Usage:
cd backend && uv run python scripts/fetch_moves_abilities.py
This script fetches all moves and abilities from PokeAPI, extracts their names
and introduced generation, and saves them to the seed data directory.
"""
import asyncio
import json
import re
from pathlib import Path
import httpx
DATA_DIR = Path(__file__).parent.parent / "src" / "app" / "seeds" / "data"
POKEAPI_BASE = "https://pokeapi.co/api/v2"
# Map generation names to numbers
GEN_MAP = {
"generation-i": 1,
"generation-ii": 2,
"generation-iii": 3,
"generation-iv": 4,
"generation-v": 5,
"generation-vi": 6,
"generation-vii": 7,
"generation-viii": 8,
"generation-ix": 9,
}
def title_case_name(name: str) -> str:
"""Convert a hyphenated PokeAPI name to title case.
Examples:
'thunder-punch' -> 'Thunder Punch'
'self-destruct' -> 'Self-Destruct'
"""
return " ".join(word.capitalize() for word in name.split("-"))
async def fetch_all_moves(client: httpx.AsyncClient) -> list[dict]:
"""Fetch all moves from PokeAPI."""
moves = []
# First, get the list of all moves
print("Fetching move list...")
url = f"{POKEAPI_BASE}/move?limit=10000"
resp = await client.get(url)
resp.raise_for_status()
data = resp.json()
move_urls = [m["url"] for m in data["results"]]
print(f"Found {len(move_urls)} moves")
# Fetch each move's details in batches
batch_size = 50
for i in range(0, len(move_urls), batch_size):
batch = move_urls[i : i + batch_size]
print(f"Fetching moves {i + 1}-{min(i + batch_size, len(move_urls))}...")
tasks = [client.get(url) for url in batch]
responses = await asyncio.gather(*tasks, return_exceptions=True)
for resp in responses:
if isinstance(resp, Exception):
print(f" Error fetching move: {resp}")
continue
if resp.status_code != 200:
print(f" HTTP {resp.status_code} for {resp.url}")
continue
move_data = resp.json()
gen_name = move_data["generation"]["name"]
introduced_gen = GEN_MAP.get(gen_name)
if introduced_gen is None:
print(f" Unknown generation: {gen_name} for move {move_data['name']}")
continue
# Get type if available
move_type = None
if move_data.get("type"):
move_type = move_data["type"]["name"]
moves.append(
{
"name": title_case_name(move_data["name"]),
"introduced_gen": introduced_gen,
"type": move_type,
}
)
# Sort by name for consistent ordering
moves.sort(key=lambda m: m["name"])
return moves
async def fetch_all_abilities(client: httpx.AsyncClient) -> list[dict]:
"""Fetch all abilities from PokeAPI."""
abilities = []
# First, get the list of all abilities
print("Fetching ability list...")
url = f"{POKEAPI_BASE}/ability?limit=10000"
resp = await client.get(url)
resp.raise_for_status()
data = resp.json()
ability_urls = [a["url"] for a in data["results"]]
print(f"Found {len(ability_urls)} abilities")
# Fetch each ability's details in batches
batch_size = 50
for i in range(0, len(ability_urls), batch_size):
batch = ability_urls[i : i + batch_size]
print(f"Fetching abilities {i + 1}-{min(i + batch_size, len(ability_urls))}...")
tasks = [client.get(url) for url in batch]
responses = await asyncio.gather(*tasks, return_exceptions=True)
for resp in responses:
if isinstance(resp, Exception):
print(f" Error fetching ability: {resp}")
continue
if resp.status_code != 200:
print(f" HTTP {resp.status_code} for {resp.url}")
continue
ability_data = resp.json()
gen_name = ability_data["generation"]["name"]
introduced_gen = GEN_MAP.get(gen_name)
if introduced_gen is None:
print(
f" Unknown generation: {gen_name} for ability {ability_data['name']}"
)
continue
abilities.append(
{
"name": title_case_name(ability_data["name"]),
"introduced_gen": introduced_gen,
}
)
# Sort by name for consistent ordering
abilities.sort(key=lambda a: a["name"])
return abilities
async def main():
print("Fetching moves and abilities from PokeAPI...")
print()
async with httpx.AsyncClient(timeout=30.0) as client:
# Fetch moves
moves = await fetch_all_moves(client)
print()
# Fetch abilities
abilities = await fetch_all_abilities(client)
print()
# Write moves to JSON
moves_path = DATA_DIR / "moves.json"
with open(moves_path, "w") as f:
json.dump(moves, f, indent=2)
f.write("\n")
print(f"Wrote {len(moves)} moves to {moves_path}")
# Write abilities to JSON
abilities_path = DATA_DIR / "abilities.json"
with open(abilities_path, "w") as f:
json.dump(abilities, f, indent=2)
f.write("\n")
print(f"Wrote {len(abilities)} abilities to {abilities_path}")
print()
print("Done!")
if __name__ == "__main__":
asyncio.run(main())