Created boilerplate setup for wilddex.db file.
.db file as 5 tables: lookalike, sightings, species species_detail and sqlite_sequence. Example .db file added
This commit is contained in:
1 parent
fe736b654b
commit
8978130b7c
2 files changed
+141
No files matched your search
@@ -0,0 +1,141 @@
|
||||
import csv
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
DB_PATH = Path(__file__).parent.parent / "wilddex.db"
|
||||
WILDLIFE_CSV = Path(__file__).parent.parent / "wildlife" / "portland_wildlife.csv"
|
||||
DEX_ENTRIES_CSV = Path(__file__).parent.parent / "wildlife" / "portland_wildlife_dex_entries.csv"
|
||||
|
||||
|
||||
def create_tables(conn: sqlite3.Connection) -> None:
|
||||
conn.executescript("""
|
||||
CREATE TABLE IF NOT EXISTS species (
|
||||
species_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
inat_taxon_id INTEGER UNIQUE NOT NULL,
|
||||
common_name TEXT NOT NULL,
|
||||
scientific_name TEXT NOT NULL,
|
||||
kingdom TEXT,
|
||||
phylum TEXT,
|
||||
class TEXT,
|
||||
"order" TEXT,
|
||||
family TEXT,
|
||||
genus TEXT,
|
||||
iconic_taxon TEXT,
|
||||
conservation_status TEXT,
|
||||
pokedex_entry TEXT,
|
||||
photo_url_thumb TEXT,
|
||||
photo_url_med TEXT,
|
||||
lat_min REAL,
|
||||
lat_max REAL,
|
||||
lng_min REAL,
|
||||
lng_max REAL,
|
||||
is_unlocked INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS species_detail (
|
||||
detail_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
species_id INTEGER NOT NULL REFERENCES species(species_id),
|
||||
size_range TEXT,
|
||||
weight_range TEXT,
|
||||
lifespan TEXT,
|
||||
diet TEXT,
|
||||
activity_period TEXT,
|
||||
habitat_type TEXT,
|
||||
behavior_notes TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sighting (
|
||||
sighting_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
species_id INTEGER NOT NULL REFERENCES species(species_id),
|
||||
observed_at TEXT,
|
||||
latitude REAL,
|
||||
longitude REAL,
|
||||
location_label TEXT,
|
||||
user_photo_path TEXT,
|
||||
notes TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS lookalike (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
species_id INTEGER NOT NULL REFERENCES species(species_id),
|
||||
lookalike_species_id INTEGER NOT NULL REFERENCES species(species_id),
|
||||
distinguishing_tip TEXT
|
||||
);
|
||||
""")
|
||||
conn.commit()
|
||||
|
||||
|
||||
def load_dex_entries(csv_path: Path) -> dict[int, str]:
|
||||
"""Return a mapping of taxon_id -> pokedex description."""
|
||||
entries = {}
|
||||
with open(csv_path, newline="", encoding="utf-8") as f:
|
||||
for row in csv.DictReader(f):
|
||||
entries[int(row["taxon_id"])] = row["description"]
|
||||
return entries
|
||||
|
||||
|
||||
def import_species(conn: sqlite3.Connection) -> None:
|
||||
dex_entries = load_dex_entries(DEX_ENTRIES_CSV)
|
||||
|
||||
with open(WILDLIFE_CSV, newline="", encoding="utf-8") as f:
|
||||
rows = list(csv.DictReader(f))
|
||||
|
||||
inserted = skipped = 0
|
||||
for row in rows:
|
||||
taxon_id = int(row["taxon_id"])
|
||||
try:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO species (
|
||||
inat_taxon_id, common_name, scientific_name,
|
||||
kingdom, phylum, class, "order", family, genus,
|
||||
iconic_taxon, photo_url_thumb, photo_url_med,
|
||||
pokedex_entry
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
taxon_id,
|
||||
row["common_name"],
|
||||
row["scientific_name"],
|
||||
row.get("kingdom"),
|
||||
row.get("phylum"),
|
||||
row.get("class"),
|
||||
row.get("order"),
|
||||
row.get("family"),
|
||||
row.get("genus"),
|
||||
row.get("iconic_taxon"),
|
||||
row.get("photo_url_thumb"),
|
||||
row.get("photo_url_med"),
|
||||
dex_entries.get(taxon_id),
|
||||
),
|
||||
)
|
||||
inserted += 1
|
||||
except sqlite3.IntegrityError:
|
||||
skipped += 1
|
||||
|
||||
conn.commit()
|
||||
print(f"Species import complete: {inserted} inserted, {skipped} skipped (already exist).")
|
||||
|
||||
|
||||
def verify_db(conn: sqlite3.Connection) -> None:
|
||||
tables = ["species", "species_detail", "sighting", "lookalike"]
|
||||
for table in tables:
|
||||
(count,) = conn.execute(f"SELECT COUNT(*) FROM {table}").fetchone()
|
||||
print(f" {table}: {count} rows")
|
||||
|
||||
print("\nSample species rows:")
|
||||
rows = conn.execute(
|
||||
"SELECT inat_taxon_id, common_name, scientific_name, iconic_taxon, pokedex_entry IS NOT NULL FROM species LIMIT 5"
|
||||
).fetchall()
|
||||
for taxon_id, common, sci, iconic, has_dex in rows:
|
||||
dex_flag = "has dex entry" if has_dex else "no dex entry"
|
||||
print(f" [{taxon_id}] {common} ({sci}) — {iconic} — {dex_flag}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with sqlite3.connect(DB_PATH) as conn:
|
||||
create_tables(conn)
|
||||
import_species(conn)
|
||||
print("\nVerification:")
|
||||
verify_db(conn)
|
||||
print(f"\nDatabase ready at {DB_PATH}")
|
||||
BIN
Binary file not shown.
Reference in new issue
Block a user