Fix linting errors across backend and frontend
Backend: auto-fix and format all ruff issues, manually fix B904/B023/ SIM117/B007/E741/F841 errors, suppress B008 (FastAPI Depends) and F821 (SQLAlchemy forward refs) in config. Frontend: allow constant exports, disable React compiler-specific rules (set-state-in-effect, preserve-manual-memoization). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -42,130 +42,139 @@ async def seed():
|
||||
"""Run the full seed process."""
|
||||
print("Starting seed...")
|
||||
|
||||
async with async_session() as session:
|
||||
async with session.begin():
|
||||
# 1. Upsert version groups
|
||||
with open(VG_JSON) as f:
|
||||
vg_data = json.load(f)
|
||||
vg_slug_to_id = await upsert_version_groups(session, vg_data)
|
||||
print(f"Version Groups: {len(vg_slug_to_id)} upserted")
|
||||
async with async_session() as session, session.begin():
|
||||
# 1. Upsert version groups
|
||||
with open(VG_JSON) as f:
|
||||
vg_data = json.load(f)
|
||||
vg_slug_to_id = await upsert_version_groups(session, vg_data)
|
||||
print(f"Version Groups: {len(vg_slug_to_id)} upserted")
|
||||
|
||||
# Build game_slug -> vg_id mapping
|
||||
game_slug_to_vg_id: dict[str, int] = {}
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
vg_id = vg_slug_to_id[vg_slug]
|
||||
for game_slug in vg_info["games"]:
|
||||
game_slug_to_vg_id[game_slug] = vg_id
|
||||
# Build game_slug -> vg_id mapping
|
||||
game_slug_to_vg_id: dict[str, int] = {}
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
vg_id = vg_slug_to_id[vg_slug]
|
||||
for game_slug in vg_info["games"]:
|
||||
game_slug_to_vg_id[game_slug] = vg_id
|
||||
|
||||
# 2. Upsert games (with version_group_id)
|
||||
games_data = load_json("games.json")
|
||||
slug_to_id = await upsert_games(session, games_data, game_slug_to_vg_id)
|
||||
print(f"Games: {len(slug_to_id)} upserted")
|
||||
# 2. Upsert games (with version_group_id)
|
||||
games_data = load_json("games.json")
|
||||
slug_to_id = await upsert_games(session, games_data, game_slug_to_vg_id)
|
||||
print(f"Games: {len(slug_to_id)} upserted")
|
||||
|
||||
# 3. Upsert Pokemon
|
||||
pokemon_data = load_json("pokemon.json")
|
||||
dex_to_id = await upsert_pokemon(session, pokemon_data)
|
||||
print(f"Pokemon: {len(dex_to_id)} upserted")
|
||||
# 3. Upsert Pokemon
|
||||
pokemon_data = load_json("pokemon.json")
|
||||
dex_to_id = await upsert_pokemon(session, pokemon_data)
|
||||
print(f"Pokemon: {len(dex_to_id)} upserted")
|
||||
|
||||
# 4. Per version group: upsert routes once, then encounters per game
|
||||
total_routes = 0
|
||||
total_encounters = 0
|
||||
route_maps_by_vg: dict[int, dict[str, int]] = {}
|
||||
# 4. Per version group: upsert routes once, then encounters per game
|
||||
total_routes = 0
|
||||
total_encounters = 0
|
||||
route_maps_by_vg: dict[int, dict[str, int]] = {}
|
||||
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
vg_id = vg_slug_to_id[vg_slug]
|
||||
game_slugs = list(vg_info["games"].keys())
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
vg_id = vg_slug_to_id[vg_slug]
|
||||
game_slugs = list(vg_info["games"].keys())
|
||||
|
||||
# Use the first game's route JSON for the shared route structure
|
||||
first_game_slug = game_slugs[0]
|
||||
routes_file = DATA_DIR / f"{first_game_slug}.json"
|
||||
if not routes_file.exists():
|
||||
print(f" {vg_slug}: no route data ({first_game_slug}.json), skipping")
|
||||
# Use the first game's route JSON for the shared route structure
|
||||
first_game_slug = game_slugs[0]
|
||||
routes_file = DATA_DIR / f"{first_game_slug}.json"
|
||||
if not routes_file.exists():
|
||||
print(f" {vg_slug}: no route data ({first_game_slug}.json), skipping")
|
||||
continue
|
||||
|
||||
routes_data = load_json(f"{first_game_slug}.json")
|
||||
if not routes_data:
|
||||
print(f" {vg_slug}: empty route data, skipping")
|
||||
continue
|
||||
|
||||
# Upsert routes once per version group
|
||||
route_map = await upsert_routes(session, vg_id, routes_data)
|
||||
route_maps_by_vg[vg_id] = route_map
|
||||
total_routes += len(route_map)
|
||||
print(f" {vg_slug}: {len(route_map)} routes")
|
||||
|
||||
# Upsert encounters per game (each game may have different encounters)
|
||||
for game_slug in game_slugs:
|
||||
game_id = slug_to_id.get(game_slug)
|
||||
if game_id is None:
|
||||
print(f" Warning: game '{game_slug}' not found, skipping")
|
||||
continue
|
||||
|
||||
routes_data = load_json(f"{first_game_slug}.json")
|
||||
if not routes_data:
|
||||
print(f" {vg_slug}: empty route data, skipping")
|
||||
game_routes_file = DATA_DIR / f"{game_slug}.json"
|
||||
if not game_routes_file.exists():
|
||||
continue
|
||||
|
||||
# Upsert routes once per version group
|
||||
route_map = await upsert_routes(session, vg_id, routes_data)
|
||||
route_maps_by_vg[vg_id] = route_map
|
||||
total_routes += len(route_map)
|
||||
print(f" {vg_slug}: {len(route_map)} routes")
|
||||
|
||||
# Upsert encounters per game (each game may have different encounters)
|
||||
for game_slug in game_slugs:
|
||||
game_id = slug_to_id.get(game_slug)
|
||||
if game_id is None:
|
||||
print(f" Warning: game '{game_slug}' not found, skipping")
|
||||
game_routes_data = load_json(f"{game_slug}.json")
|
||||
for route in game_routes_data:
|
||||
route_id = route_map.get(route["name"])
|
||||
if route_id is None:
|
||||
print(f" Warning: route '{route['name']}' not found")
|
||||
continue
|
||||
|
||||
game_routes_file = DATA_DIR / f"{game_slug}.json"
|
||||
if not game_routes_file.exists():
|
||||
continue
|
||||
# Parent routes may have empty encounters
|
||||
if route["encounters"]:
|
||||
enc_count = await upsert_route_encounters(
|
||||
session,
|
||||
route_id,
|
||||
route["encounters"],
|
||||
dex_to_id,
|
||||
game_id,
|
||||
)
|
||||
total_encounters += enc_count
|
||||
|
||||
game_routes_data = load_json(f"{game_slug}.json")
|
||||
for route in game_routes_data:
|
||||
route_id = route_map.get(route["name"])
|
||||
if route_id is None:
|
||||
print(f" Warning: route '{route['name']}' not found")
|
||||
# Handle child routes
|
||||
for child in route.get("children", []):
|
||||
child_id = route_map.get(child["name"])
|
||||
if child_id is None:
|
||||
print(
|
||||
f" Warning: child route '{child['name']}' not found"
|
||||
)
|
||||
continue
|
||||
|
||||
# Parent routes may have empty encounters
|
||||
if route["encounters"]:
|
||||
enc_count = await upsert_route_encounters(
|
||||
session, route_id, route["encounters"],
|
||||
dex_to_id, game_id,
|
||||
)
|
||||
total_encounters += enc_count
|
||||
enc_count = await upsert_route_encounters(
|
||||
session,
|
||||
child_id,
|
||||
child["encounters"],
|
||||
dex_to_id,
|
||||
game_id,
|
||||
)
|
||||
total_encounters += enc_count
|
||||
|
||||
# Handle child routes
|
||||
for child in route.get("children", []):
|
||||
child_id = route_map.get(child["name"])
|
||||
if child_id is None:
|
||||
print(f" Warning: child route '{child['name']}' not found")
|
||||
continue
|
||||
print(f" {game_slug}: encounters loaded")
|
||||
|
||||
enc_count = await upsert_route_encounters(
|
||||
session, child_id, child["encounters"],
|
||||
dex_to_id, game_id,
|
||||
)
|
||||
total_encounters += enc_count
|
||||
print(f"\nTotal routes: {total_routes}")
|
||||
print(f"Total encounters: {total_encounters}")
|
||||
|
||||
print(f" {game_slug}: encounters loaded")
|
||||
# 5. Per version group: upsert bosses
|
||||
total_bosses = 0
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
vg_id = vg_slug_to_id[vg_slug]
|
||||
first_game_slug = list(vg_info["games"].keys())[0]
|
||||
bosses_file = DATA_DIR / f"{first_game_slug}-bosses.json"
|
||||
if not bosses_file.exists():
|
||||
continue
|
||||
|
||||
print(f"\nTotal routes: {total_routes}")
|
||||
print(f"Total encounters: {total_encounters}")
|
||||
bosses_data = load_json(f"{first_game_slug}-bosses.json")
|
||||
if not bosses_data:
|
||||
continue
|
||||
|
||||
# 5. Per version group: upsert bosses
|
||||
total_bosses = 0
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
vg_id = vg_slug_to_id[vg_slug]
|
||||
first_game_slug = list(vg_info["games"].keys())[0]
|
||||
bosses_file = DATA_DIR / f"{first_game_slug}-bosses.json"
|
||||
if not bosses_file.exists():
|
||||
continue
|
||||
route_name_to_id = route_maps_by_vg.get(vg_id, {})
|
||||
boss_count = await upsert_bosses(
|
||||
session, vg_id, bosses_data, dex_to_id, route_name_to_id
|
||||
)
|
||||
total_bosses += boss_count
|
||||
print(f" {vg_slug}: {boss_count} bosses")
|
||||
|
||||
bosses_data = load_json(f"{first_game_slug}-bosses.json")
|
||||
if not bosses_data:
|
||||
continue
|
||||
print(f"Total bosses: {total_bosses}")
|
||||
|
||||
route_name_to_id = route_maps_by_vg.get(vg_id, {})
|
||||
boss_count = await upsert_bosses(session, vg_id, bosses_data, dex_to_id, route_name_to_id)
|
||||
total_bosses += boss_count
|
||||
print(f" {vg_slug}: {boss_count} bosses")
|
||||
|
||||
print(f"Total bosses: {total_bosses}")
|
||||
|
||||
# 6. Upsert evolutions
|
||||
evolutions_path = DATA_DIR / "evolutions.json"
|
||||
if evolutions_path.exists():
|
||||
evolutions_data = load_json("evolutions.json")
|
||||
evo_count = await upsert_evolutions(session, evolutions_data, dex_to_id)
|
||||
print(f"Evolutions: {evo_count} upserted")
|
||||
else:
|
||||
print("No evolutions.json found, skipping evolutions")
|
||||
# 6. Upsert evolutions
|
||||
evolutions_path = DATA_DIR / "evolutions.json"
|
||||
if evolutions_path.exists():
|
||||
evolutions_data = load_json("evolutions.json")
|
||||
evo_count = await upsert_evolutions(session, evolutions_data, dex_to_id)
|
||||
print(f"Evolutions: {evo_count} upserted")
|
||||
else:
|
||||
print("No evolutions.json found, skipping evolutions")
|
||||
|
||||
print("Seed complete!")
|
||||
|
||||
@@ -180,7 +189,9 @@ async def verify():
|
||||
games_count = (await session.execute(select(func.count(Game.id)))).scalar()
|
||||
pokemon_count = (await session.execute(select(func.count(Pokemon.id)))).scalar()
|
||||
routes_count = (await session.execute(select(func.count(Route.id)))).scalar()
|
||||
enc_count = (await session.execute(select(func.count(RouteEncounter.id)))).scalar()
|
||||
enc_count = (
|
||||
await session.execute(select(func.count(RouteEncounter.id)))
|
||||
).scalar()
|
||||
boss_count = (await session.execute(select(func.count(BossBattle.id)))).scalar()
|
||||
|
||||
print(f"Version Groups: {vg_count}")
|
||||
@@ -328,7 +339,7 @@ async def _export_routes(session: AsyncSession, vg_data: dict):
|
||||
games_by_slug = {g.slug: g for g in game_result.scalars().all()}
|
||||
|
||||
exported = 0
|
||||
for vg_slug, vg_info in vg_data.items():
|
||||
for _vg_slug, vg_info in vg_data.items():
|
||||
for game_slug in vg_info["games"]:
|
||||
game = games_by_slug.get(game_slug)
|
||||
if game is None or game.version_group_id is None:
|
||||
@@ -356,11 +367,9 @@ async def _export_routes(session: AsyncSession, vg_data: dict):
|
||||
if r.parent_route_id is not None:
|
||||
children_by_parent.setdefault(r.parent_route_id, []).append(r)
|
||||
|
||||
def format_encounters(route: Route) -> list[dict]:
|
||||
def format_encounters(route: Route, _game: Game = game) -> list[dict]:
|
||||
game_encounters = [
|
||||
enc
|
||||
for enc in route.route_encounters
|
||||
if enc.game_id == game.id
|
||||
enc for enc in route.route_encounters if enc.game_id == _game.id
|
||||
]
|
||||
return [
|
||||
{
|
||||
@@ -384,17 +393,20 @@ async def _export_routes(session: AsyncSession, vg_data: dict):
|
||||
data["pinwheel_zone"] = route.pinwheel_zone
|
||||
return data
|
||||
|
||||
def format_route(route: Route) -> dict:
|
||||
def format_route(
|
||||
route: Route,
|
||||
_children_by_parent: dict[int, list[Route]] = children_by_parent,
|
||||
) -> dict:
|
||||
data: dict = {
|
||||
"name": route.name,
|
||||
"order": route.order,
|
||||
"encounters": format_encounters(route),
|
||||
}
|
||||
children = children_by_parent.get(route.id, [])
|
||||
children = _children_by_parent.get(route.id, [])
|
||||
if children:
|
||||
data["children"] = [
|
||||
format_child(c)
|
||||
for c in sorted(children, key=lambda r: r.order)
|
||||
for c in sorted(children, key=lambda route: route.order)
|
||||
]
|
||||
return data
|
||||
|
||||
@@ -444,7 +456,9 @@ def _download_image(
|
||||
|
||||
if filename not in downloaded:
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
req = urllib.request.Request(url, headers={"User-Agent": "nuzlocke-tracker/1.0"})
|
||||
req = urllib.request.Request(
|
||||
url, headers={"User-Agent": "nuzlocke-tracker/1.0"}
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
dest.write_bytes(resp.read())
|
||||
@@ -496,37 +510,45 @@ async def _export_bosses(session: AsyncSession, vg_data: dict):
|
||||
if badge_image_url and b.badge_name:
|
||||
badge_slug = _slugify(b.badge_name)
|
||||
badge_image_url = _download_image(
|
||||
badge_image_url, badge_dir, badge_slug, downloaded_badges,
|
||||
badge_image_url,
|
||||
badge_dir,
|
||||
badge_slug,
|
||||
downloaded_badges,
|
||||
)
|
||||
|
||||
if sprite_url:
|
||||
sprite_slug = _slugify(b.name)
|
||||
sprite_url = _download_image(
|
||||
sprite_url, sprite_dir, sprite_slug, downloaded_sprites,
|
||||
sprite_url,
|
||||
sprite_dir,
|
||||
sprite_slug,
|
||||
downloaded_sprites,
|
||||
)
|
||||
|
||||
data.append({
|
||||
"name": b.name,
|
||||
"boss_type": b.boss_type,
|
||||
"specialty_type": b.specialty_type,
|
||||
"badge_name": b.badge_name,
|
||||
"badge_image_url": badge_image_url,
|
||||
"level_cap": b.level_cap,
|
||||
"order": b.order,
|
||||
"after_route_name": b.after_route.name if b.after_route else None,
|
||||
"location": b.location,
|
||||
"section": b.section,
|
||||
"sprite_url": sprite_url,
|
||||
"pokemon": [
|
||||
{
|
||||
"pokeapi_id": bp.pokemon.pokeapi_id,
|
||||
"pokemon_name": bp.pokemon.name,
|
||||
"level": bp.level,
|
||||
"order": bp.order,
|
||||
}
|
||||
for bp in sorted(b.pokemon, key=lambda p: p.order)
|
||||
],
|
||||
})
|
||||
data.append(
|
||||
{
|
||||
"name": b.name,
|
||||
"boss_type": b.boss_type,
|
||||
"specialty_type": b.specialty_type,
|
||||
"badge_name": b.badge_name,
|
||||
"badge_image_url": badge_image_url,
|
||||
"level_cap": b.level_cap,
|
||||
"order": b.order,
|
||||
"after_route_name": b.after_route.name if b.after_route else None,
|
||||
"location": b.location,
|
||||
"section": b.section,
|
||||
"sprite_url": sprite_url,
|
||||
"pokemon": [
|
||||
{
|
||||
"pokeapi_id": bp.pokemon.pokeapi_id,
|
||||
"pokemon_name": bp.pokemon.name,
|
||||
"level": bp.level,
|
||||
"order": bp.order,
|
||||
}
|
||||
for bp in sorted(b.pokemon, key=lambda p: p.order)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
_write_json(f"{first_game_slug}-bosses.json", data)
|
||||
exported += 1
|
||||
|
||||
Reference in New Issue
Block a user