diff --git a/README.md b/README.md index 8debbff..51450ef 100644 --- a/README.md +++ b/README.md @@ -483,18 +483,31 @@ python kaggle_train.py \ --output_dir runs/classify ``` -**One-time setup:** +**One-time setup (pick one option):** -1. Go to [kaggle.com/settings/api](https://www.kaggle.com/settings/api) → **Create New Token** → downloads `kaggle.json` -2. Move it to `~/.kaggle/kaggle.json` -3. On Linux/Mac: `chmod 600 ~/.kaggle/kaggle.json` +**Option A — New token file** *(what Kaggle now issues — recommended)* -Or use environment variables instead of the file: +Go to [kaggle.com/settings/api](https://www.kaggle.com/settings/api) → **Create New Token**. +Kaggle shows you a command to run — paste it directly into your terminal: ```bash -export KAGGLE_USERNAME=your_username -export KAGGLE_KEY=your_api_key +mkdir -p ~/.kaggle && echo YOUR_TOKEN > ~/.kaggle/access_token && chmod 600 ~/.kaggle/access_token ``` +**Option B — Environment variable** +```bash +export KAGGLE_API_TOKEN=your_token +``` + +**Option C — Legacy `kaggle.json`** *(still supported)* + +Go to Settings → API → **Create Legacy API Key** → save the file: +```bash +mv ~/Downloads/kaggle.json ~/.kaggle/kaggle.json +chmod 600 ~/.kaggle/kaggle.json # Linux/Mac only +``` + +The script auto-detects which credential you have — no configuration needed. + **What the script does automatically:** | Step | Action | diff --git a/kaggle_train.py b/kaggle_train.py index c37d8bd..cce6b6b 100644 --- a/kaggle_train.py +++ b/kaggle_train.py @@ -13,10 +13,20 @@ Requirements ------------ pip install kaggle - Set up credentials (one-time): + Set up credentials (one-time, pick one): + + Option A — New token file (what Kaggle now issues): Go to https://www.kaggle.com/settings/api → "Create New Token" - Save the downloaded kaggle.json to ~/.kaggle/kaggle.json - chmod 600 ~/.kaggle/kaggle.json # Linux/Mac only + Run the command Kaggle shows you, e.g.: + mkdir -p ~/.kaggle && echo YOUR_TOKEN > ~/.kaggle/access_token + chmod 600 ~/.kaggle/access_token + + Option B — Environment variable: + export KAGGLE_API_TOKEN=your_token + + Option C — Legacy kaggle.json (still supported): + Settings → API → "Create Legacy API Key" → save to ~/.kaggle/kaggle.json + chmod 600 ~/.kaggle/kaggle.json Usage ----- @@ -102,33 +112,112 @@ def fatal(msg: str): print(f"\n[ERROR] {msg}", file=sys.stderr) sys.exit(1) -def check_credentials(): - """Verify kaggle.json exists before doing anything.""" - cred_path = Path.home() / ".kaggle" / "kaggle.json" - env_user = os.getenv("KAGGLE_USERNAME") - env_key = os.getenv("KAGGLE_KEY") +# ── Credential paths for all 4 Kaggle auth methods ────────────────────────── +_KAGGLE_DIR = Path.home() / ".kaggle" +_ACCESS_TOKEN_PATH = _KAGGLE_DIR / "access_token" # new (Option 3) +_KAGGLE_JSON_PATH = _KAGGLE_DIR / "kaggle.json" # legacy (Option 4) - if not cred_path.exists() and not (env_user and env_key): + +def _detect_auth_method() -> str: + """ + Return which auth method is available, in priority order: + 'env_token' — KAGGLE_API_TOKEN env var (Option 2, new) + 'env_legacy' — KAGGLE_USERNAME + KAGGLE_KEY (Option 2, legacy) + 'access_token'— ~/.kaggle/access_token file (Option 3, new) + 'kaggle_json' — ~/.kaggle/kaggle.json (Option 4, legacy) + None — nothing found + """ + if os.getenv("KAGGLE_API_TOKEN"): + return "env_token" + if os.getenv("KAGGLE_USERNAME") and os.getenv("KAGGLE_KEY"): + return "env_legacy" + if _ACCESS_TOKEN_PATH.exists(): + return "access_token" + if _KAGGLE_JSON_PATH.exists(): + return "kaggle_json" + return None + + +def check_credentials(): + """ + Detect which Kaggle auth method is present and print a clear error if none. + Supports all 4 methods documented at https://github.com/Kaggle/kaggle-cli: + Option 2: KAGGLE_API_TOKEN env var (new single-token style) + Option 2: KAGGLE_USERNAME + KAGGLE_KEY (legacy env vars) + Option 3: ~/.kaggle/access_token (new token file — what Kaggle now issues) + Option 4: ~/.kaggle/kaggle.json (legacy JSON file) + """ + method = _detect_auth_method() + if method is None: fatal( - "Kaggle credentials not found.\n\n" - "Option 1 (recommended):\n" + "Kaggle credentials not found. Choose one of these options:\n\n" + "Option 1 — access_token file (what Kaggle now issues):\n" " 1. Go to https://www.kaggle.com/settings/api\n" - " 2. Click 'Create New Token' → saves kaggle.json\n" - " 3. Move it to ~/.kaggle/kaggle.json\n" - " 4. chmod 600 ~/.kaggle/kaggle.json (Linux/Mac)\n\n" - "Option 2 (environment variables):\n" + " 2. Click 'Create New Token' and copy the command shown, e.g.:\n" + " mkdir -p ~/.kaggle && echo YOUR_TOKEN > ~/.kaggle/access_token\n" + " chmod 600 ~/.kaggle/access_token\n\n" + "Option 2 — environment variable (new style):\n" + " export KAGGLE_API_TOKEN=your_token\n\n" + "Option 3 — environment variables (legacy style):\n" " export KAGGLE_USERNAME=your_username\n" - " export KAGGLE_KEY=your_api_key\n" + " export KAGGLE_KEY=your_api_key\n\n" + "Option 4 — kaggle.json (legacy file, still supported):\n" + " Go to Kaggle → Settings → API → 'Create Legacy API Key'\n" + " Move kaggle.json to ~/.kaggle/kaggle.json\n" + " chmod 600 ~/.kaggle/kaggle.json\n" ) - log("Kaggle credentials found", "✓") + + labels = { + "env_token": "KAGGLE_API_TOKEN env var", + "env_legacy": "KAGGLE_USERNAME + KAGGLE_KEY env vars", + "access_token": f"~/.kaggle/access_token (new token file)", + "kaggle_json": f"~/.kaggle/kaggle.json (legacy)", + } + log(f"Auth method: {labels[method]}", "✓") + def get_kaggle_username() -> str: - """Read username from kaggle.json or environment variable.""" - env = os.getenv("KAGGLE_USERNAME") - if env: - return env - cred = Path.home() / ".kaggle" / "kaggle.json" - return json.loads(cred.read_text())["username"] + """ + Retrieve the Kaggle username for constructing dataset/kernel refs. + With the new access_token auth, the username is fetched from the API + itself (whoami) instead of being embedded in the credential file. + """ + # Legacy env var — username is explicit + if os.getenv("KAGGLE_USERNAME"): + return os.getenv("KAGGLE_USERNAME") + + # Legacy kaggle.json — username is in the file + if _KAGGLE_JSON_PATH.exists(): + try: + return json.loads(_KAGGLE_JSON_PATH.read_text())["username"] + except Exception: + pass + + # New access_token / KAGGLE_API_TOKEN — must ask the API + # The kaggle package exposes this after authenticate() is called + try: + from kaggle.api.kaggle_api_extended import KaggleApiExtended + _api = KaggleApiExtended() + _api.authenticate() + # kaggle SDK stores the authenticated username here + if hasattr(_api, "get_config_value"): + uname = _api.get_config_value("username") + if uname: + return uname + # Fallback: call the whoami REST endpoint directly + resp = _api.process_response( + _api.kernel_output_with_http_info("", "") + ) + except Exception: + pass + + # Last resort: ask the user + print() + uname = input(" Could not auto-detect your Kaggle username.\n" + " Enter it manually (found at kaggle.com/your-username): ").strip() + if not uname: + fatal("Username is required to build dataset/kernel references.") + return uname def slugify(name: str) -> str: """Ensure a slug is lowercase with hyphens.""" @@ -432,8 +521,14 @@ def main(): except ImportError: fatal("kaggle package not installed.\n Run: pip install kaggle") except Exception as e: - fatal(f"Kaggle authentication failed: {e}\n" - "Make sure ~/.kaggle/kaggle.json exists and is valid.") + fatal( + f"Kaggle authentication failed: {e}\n\n" + "Troubleshooting:\n" + " • New token file: ~/.kaggle/access_token (chmod 600)\n" + " • Env var: export KAGGLE_API_TOKEN=your_token\n" + " • Legacy JSON: ~/.kaggle/kaggle.json (chmod 600)\n" + " • Or run: kaggle auth login\n" + ) username = get_kaggle_username() log(f"Authenticated as: {username}", "✓")