From ca35b36efa5928ae4ed1ee111e4044c44793874e Mon Sep 17 00:00:00 2001 From: Petru Paler Date: Mon, 12 Jan 2026 17:45:01 +0000 Subject: [PATCH] Fix garth token serialization using TypeAdapter for Pydantic dataclasses Garth's OAuth1Token and OAuth2Token are Pydantic dataclasses, not BaseModel subclasses, so they require TypeAdapter for serialization instead of model_dump(). Also adds user-friendly error handling for authentication failures. Co-Authored-By: Claude Opus 4.5 --- scripts/garmin_auth.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/garmin_auth.py b/scripts/garmin_auth.py index 8a64ac5..dbd0e5f 100644 --- a/scripts/garmin_auth.py +++ b/scripts/garmin_auth.py @@ -10,11 +10,15 @@ Usage: python3 garmin_auth.py """ import json +import sys from datetime import datetime from getpass import getpass try: import garth + from garth.auth_tokens import OAuth1Token, OAuth2Token + from garth.exc import GarthHTTPError + from pydantic import TypeAdapter except ImportError: print("Error: garth library not installed.") print("Please install it with: pip install garth") @@ -24,11 +28,25 @@ email = input("Garmin email: ") password = getpass("Garmin password: ") # MFA handled automatically - prompts if needed -garth.login(email, password) +try: + garth.login(email, password) +except GarthHTTPError as e: + if "401" in str(e): + print("\nError: Invalid email or password.", file=sys.stderr) + else: + print(f"\nError: Authentication failed - {e}", file=sys.stderr) + exit(1) +except Exception as e: + print(f"\nError: {e}", file=sys.stderr) + exit(1) + +# Serialize Pydantic dataclasses using TypeAdapter +oauth1_adapter = TypeAdapter(OAuth1Token) +oauth2_adapter = TypeAdapter(OAuth2Token) tokens = { - "oauth1": garth.client.oauth1_token.model_dump(), - "oauth2": garth.client.oauth2_token.model_dump(), + "oauth1": oauth1_adapter.dump_python(garth.client.oauth1_token, mode='json'), + "oauth2": oauth2_adapter.dump_python(garth.client.oauth2_token, mode='json'), "expires_at": garth.client.oauth2_token.expires_at }