bank-fraud / training /fetch_data.py
root
init
942b115
Raw
History Blame Contribute Delete
4.17 kB
"""Kaggle PaySim dataset download script (SETUP-02).
Downloads the `ealaxi/paysim1` dataset from Kaggle into `data/` and
unzips it so the PaySim CSV lands directly under `data/`.
Note: the dataset originally lived at `ntnu-testimon/paysim1`; that slug now
returns HTTP 403 (dataset moved/retired under the old owner). `ealaxi/paysim1`
is the current live mirror of the same PaySim simulation output (same
~6.36M-row schema: step, type, amount, nameOrig/nameDest, balances, isFraud,
isFlaggedFraud).
Reads `KAGGLE_USERNAME`/`KAGGLE_KEY` from the environment (via `.env`,
loaded with python-dotenv) and fails loud -- naming the missing variable(s)
-- BEFORE attempting any network call or importing the `kaggle` package.
This check must run before `import kaggle`: the installed `kaggle` client
authenticates eagerly as a side effect of importing the package (any
submodule import triggers it), which would otherwise surface its own,
less specific error before our validation ever runs.
Idempotent: if a PaySim CSV already exists under `data/`, the download is
skipped and the existing path is reported.
Usage:
python training/fetch_data.py
"""
from __future__ import annotations
import sys
from pathlib import Path
from dotenv import load_dotenv
DATASET = "ealaxi/paysim1"
DATA_DIR = Path(__file__).resolve().parent.parent / "data"
class FetchDataError(RuntimeError):
"""Raised when the PaySim dataset cannot be fetched.
Messages never include credential values -- only variable names.
"""
def _require_kaggle_credentials() -> None:
"""Fail loud, naming any missing/empty Kaggle credential env var.
Runs before any network call and before `kaggle` is imported.
"""
import os
missing = [
name
for name in ("KAGGLE_USERNAME", "KAGGLE_KEY")
if not os.environ.get(name, "").strip()
]
if missing:
raise FetchDataError(
"Missing required Kaggle credential(s) in the environment: "
f"{', '.join(missing)}. Set them in .env (see README) before "
"running training/fetch_data.py. No network call was made."
)
def _existing_csv() -> Path | None:
if not DATA_DIR.exists():
return None
csvs = sorted(DATA_DIR.glob("*.csv"))
return csvs[0] if csvs else None
def main() -> Path:
load_dotenv()
_require_kaggle_credentials()
existing = _existing_csv()
if existing is not None:
print(f"PaySim CSV already present, skipping download: {existing}")
return existing
# Imported lazily, after credential validation above: importing the
# `kaggle` package (any submodule) triggers its own eager
# authentication check as a side effect of import.
from kaggle.api.kaggle_api_extended import KaggleApi
from requests.exceptions import HTTPError
DATA_DIR.mkdir(parents=True, exist_ok=True)
try:
api = KaggleApi()
api.authenticate()
print(f"Downloading {DATASET} into {DATA_DIR} ...")
api.dataset_download_files(DATASET, path=str(DATA_DIR), unzip=True)
except HTTPError as exc:
status = exc.response.status_code if exc.response is not None else "unknown"
raise FetchDataError(
f"Kaggle API request failed (HTTP {status}) while downloading "
f"'{DATASET}'. This is a Kaggle-side authorization/response "
"issue, not a missing-credential problem -- KAGGLE_USERNAME/"
"KAGGLE_KEY were present and accepted by the auth step. "
"Verify the API token is current (regenerate at "
"https://www.kaggle.com/settings/api if needed) and that the "
"account has access to this dataset."
) from exc
csv_path = _existing_csv()
if csv_path is None:
raise FetchDataError(
f"Download completed but no .csv file was found under {DATA_DIR}. "
"Check the Kaggle dataset contents."
)
print(f"PaySim CSV available at: {csv_path}")
return csv_path
if __name__ == "__main__":
try:
main()
except FetchDataError as exc:
print(f"ERROR: {exc}", file=sys.stderr)
sys.exit(1)