### Setup Development Environment (Bash) Source: https://github.com/felixnext/whoopy/blob/main/readme.md Commands to clone the Whoopy repository and install development dependencies using 'uv sync --all-extras'. This sets up the project for local development. ```bash # Clone the repository git clone https://github.com/felixnext/whoopy.git cd whoopy # Install with development dependencies uv sync --all-extras ``` -------------------------------- ### Building and Installing the Package (Bash) Source: https://github.com/felixnext/whoopy/blob/main/readme.md Commands to build the Whoopy package into wheel and sdist formats using 'uv build', and then install the built wheel locally for testing purposes. ```bash # Build wheel and sdist uv build # Install locally to test uv pip install dist/whoopy-*.whl ``` -------------------------------- ### Install Whoopy Package Source: https://github.com/felixnext/whoopy/blob/main/readme.md Installs the Whoopy Python client using pip or uv. For development, it includes installing extra dependencies for testing and linting. ```bash pip install whoopy ``` ```bash uv add whoopy ``` ```bash git clone https://github.com/felixnext/whoopy.git cd whoopy uv sync --all-extras # Or install with pip pip install -e ".[dev]" ``` -------------------------------- ### Running the Data Explorer Tool (Bash) Source: https://github.com/felixnext/whoopy/blob/main/readme.md Instructions to install dependencies for the Streamlit-based data explorer and then run the explorer application. This tool is used for visualizing WHOOP data. ```bash # Install explorer dependencies uv sync --extra explorer # Run the explorer cd tools/explorer && uv run streamlit run explorer.py ``` -------------------------------- ### Python API Client Usage Examples Source: https://github.com/felixnext/whoopy/blob/main/readme.md Python code snippets demonstrating how to use the Whoopy client to interact with the WHOOP API. Examples cover fetching user profile, measurements, cycles, sleep data, recovery data, and workouts. Assumes a client instance is already initialized. ```python # User data profile = client.user.get_profile() measurements = client.user.get_body_measurements() # Cycles (daily summaries) cycle = client.cycles.get_by_id(12345) cycles = client.cycles.get_all(start="2024-01-01", end="2024-01-31") # Sleep sleep = client.sleep.get_by_id("uuid-here") sleep_df = client.sleep.get_dataframe(start="2024-01-01") # Recovery recovery = client.recovery.get_for_cycle(12345) recoveries = client.recovery.get_all() # Workouts workout = client.workouts.get_by_id("uuid-here") workouts = client.workouts.get_by_sport("running", start="2024-01-01") ``` -------------------------------- ### Running Tests with Pytest (Bash) Source: https://github.com/felixnext/whoopy/blob/main/readme.md Bash commands to execute tests using pytest. Includes options for running all tests, running with coverage, and running specific test files. Requires pytest to be installed. ```bash # Run all tests uv run pytest # Run with coverage uv run pytest --cov=whoopy # Run specific test file uv run pytest tests/test_client.py ``` -------------------------------- ### Get Workouts by Date Range using Whoopy Source: https://context7.com/felixnext/whoopy/llms.txt Fetches workout data for a specified date range, defaulting to the last 7 days. It iterates through the retrieved workouts and prints key details such as sport name, ID, start time, duration, and performance metrics like strain, heart rate, and energy expenditure. Includes a breakdown of time spent in different heart rate zones. ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get workouts from last 7 days workouts = client.workouts.get_all( start=datetime.now() - timedelta(days=7), end=datetime.now(), limit_per_page=25, max_records=50 ) print(f"Found {len(workouts)} workouts\n") for workout in workouts: print(f"Workout: {workout.sport_name}") print(f" ID: {workout.id}") print(f" Start: {workout.start}") print(f" Duration: {workout.duration_hours:.2f} hours") print(f" Timezone: {workout.timezone_offset}") if workout.score: print(f" Strain: {workout.score.strain:.2f}") print(f" Avg HR: {workout.score.average_heart_rate} bpm") print(f" Max HR: {workout.score.max_heart_rate} bpm") print(f" Energy: {workout.score.kilojoule:.1f} kJ") print(f" Calories: {workout.score.calories:.0f} cal") # Zone time breakdown if hasattr(workout.score, 'zone_duration'): zone = workout.score.zone_duration print(f" Zone 0: {zone.zone_zero_milli / 60000:.1f} min" if zone.zone_zero_milli else "") print(f" Zone 1: {zone.zone_one_milli / 60000:.1f} min" if zone.zone_one_milli else "") print(f" Zone 2: {zone.zone_two_milli / 60000:.1f} min" if zone.zone_two_milli else "") print(f" Zone 3: {zone.zone_three_milli / 60000:.1f} min" if zone.zone_three_milli else "") print(f" Zone 4: {zone.zone_four_milli / 60000:.1f} min" if zone.zone_four_milli else "") print(f" Zone 5: {zone.zone_five_milli / 60000:.1f} min" if zone.zone_five_milli else "") print() ``` -------------------------------- ### Async Iterator for Large Datasets (Python) Source: https://context7.com/felixnext/whoopy/llms.txt This example demonstrates how to efficiently process large datasets, like cycles over 90 days, using an asynchronous iterator with the WhoopClientV2. It avoids loading all data into memory at once, processing each item as it's received. Requires the 'whoopy' library and 'asyncio'. ```python import asyncio from whoopy import WhoopClientV2 from datetime import datetime, timedelta async def process_large_dataset(): async with WhoopClientV2.from_config() as client: end = datetime.now() start = end - timedelta(days=90) print("Processing all cycles from last 90 days...") cycle_count = 0 total_strain = 0 # Iterate through all cycles without loading everything into memory async for cycle in client.cycles.iterate( start=start, end=end, limit_per_page=25 ): cycle_count += 1 if cycle.score: total_strain += cycle.score.strain # Process each cycle as it arrives if cycle_count % 10 == 0: print(f"Processed {cycle_count} cycles...") if cycle_count > 0: print(f"\nTotal cycles: {cycle_count}") print(f"Average strain: {total_strain / cycle_count:.2f}") asyncio.run(process_large_dataset()) ``` -------------------------------- ### Concurrent Data Fetching with Async Client (Python) Source: https://context7.com/felixnext/whoopy/llms.txt This example showcases concurrent data fetching from the Whoopy API using the asynchronous WhoopClientV2. It retrieves profile, measurements, cycles, sleep, and workout data simultaneously and handles potential exceptions for each request. Requires the 'whoopy' library and 'asyncio'. ```python import asyncio from whoopy import WhoopClientV2 from datetime import datetime, timedelta async def fetch_all_data(): # Create async client from config async with WhoopClientV2.from_config() as client: # Define date range end = datetime.now() start = end - timedelta(days=7) # Fetch multiple data types concurrently profile_task = client.user.get_profile() measurements_task = client.user.get_body_measurements() cycles_task = client.cycles.get_all(start=start, end=end) sleep_task = client.sleep.get_all(start=start, end=end) workouts_task = client.workouts.get_all(start=start, end=end, max_records=10) # Wait for all requests to complete profile, measurements, cycles, sleep, workouts = await asyncio.gather( profile_task, measurements_task, cycles_task, sleep_task, workouts_task, return_exceptions=True # Don't fail if one request fails ) # Process results if not isinstance(profile, Exception): print(f"User: {profile.first_name} {profile.last_name}") if not isinstance(measurements, Exception): print(f"Weight: {measurements.weight_kilogram:.1f} kg") if not isinstance(cycles, Exception): print(f"Cycles: {len(cycles)}") if not isinstance(sleep, Exception): print(f"Sleep activities: {len(sleep)}") if not isinstance(workouts, Exception): print(f"Workouts: {len(workouts)}") # Run async function asyncio.run(fetch_all_data()) ``` -------------------------------- ### Filter Workouts by Sport Type (Python) Source: https://context7.com/felixnext/whoopy/llms.txt This snippet demonstrates how to filter workouts by a specific sport type, such as 'Running', within a given date range using the WhoopClient. It calculates basic statistics for the filtered workouts. Ensure the 'whoopy' library is installed and configured. ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get all running workouts from last 30 days running_workouts = client.workouts.get_by_sport( sport_name="Running", start=datetime.now() - timedelta(days=30), end=datetime.now(), limit_per_page=25 ) print(f"Found {len(running_workouts)} running workouts\n") # Calculate statistics total_distance = 0 total_calories = 0 total_duration = 0 avg_strain = 0 for workout in running_workouts: total_duration += workout.duration_hours if workout.score: total_calories += workout.score.calories avg_strain += workout.score.strain if running_workouts: print(f"Running Statistics (last 30 days):") print(f" Total workouts: {len(running_workouts)}") print(f" Total duration: {total_duration:.1f} hours") print(f" Total calories: {total_calories:.0f} cal") print(f" Average strain: {avg_strain / len(running_workouts):.2f}") print(f" Avg workout duration: {total_duration / len(running_workouts):.2f} hours") ``` -------------------------------- ### Retrieve Recent WHOOP Cycles with Pagination Source: https://context7.com/felixnext/whoopy/llms.txt Retrieves physiological cycles from the WHOOP API for a specified date range using the WhoopClient. This example demonstrates how to fetch all cycles within the last 7 days, automatically handling pagination. It also shows how to access detailed information for each cycle, including strain, heart rate, and energy expenditure. The client is initialized from configuration. ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get cycles from last 7 days end_date = datetime.now() start_date = end_date - timedelta(days=7) # Get all cycles (automatically handles pagination) cycles = client.cycles.get_all( start=start_date, end=end_date, limit_per_page=25, max_records=100 # Optional: limit total records ) print(f"Found {len(cycles)} cycles") for cycle in cycles: print(f"\nCycle {cycle.id}:") print(f" Start: {cycle.start}") print(f" End: {cycle.end or 'Ongoing'}") print(f" Duration: {cycle.duration_hours:.1f} hours" if cycle.duration_hours else " In progress") print(f" Complete: {cycle.is_complete}") if cycle.score: print(f" Strain: {cycle.score.strain:.2f}") print(f" Avg HR: {cycle.score.average_heart_rate} bpm") print(f" Max HR: {cycle.score.max_heart_rate} bpm") print(f" Energy: {cycle.score.kilojoule:.1f} kJ") print(f" Calories: {cycle.score.calories:.0f} cal") ``` -------------------------------- ### Access Sleep Activities with Detailed Metrics using Whoopy API Source: https://context7.com/felixnext/whoopy/llms.txt This example shows how to retrieve a list of sleep activities from the last 30 days using the Whoopy API. It iterates through the activities, printing key details like duration, nap status, and sleep stage breakdowns. It utilizes the `whoopy` library and requires `datetime` and `timedelta` for date calculations. ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get sleep data from last 30 days sleep_activities = client.sleep.get_all( start=datetime.now() - timedelta(days=30), end=datetime.now(), limit_per_page=25 ) print(f"Found {len(sleep_activities)} sleep activities\n") for sleep in sleep_activities: print(f"Sleep ID: {sleep.id}") print(f" Date: {sleep.start}") print(f" Duration: {sleep.duration_hours:.1f} hours") print(f" Nap: {'Yes' if sleep.nap else 'No'}") print(f" Quality Duration: {sleep.quality_duration_hours:.1f} hours" if sleep.quality_duration_hours else "") print(f" Latency: {sleep.latency_hours:.1f} hours" if sleep.latency_hours else "") if sleep.score and sleep.score.stage_summary: summary = sleep.score.stage_summary # Convert milliseconds to hours for readability light_hrs = summary.total_light_sleep_time_milli / 3600000 deep_hrs = summary.total_slow_wave_sleep_time_milli / 3600000 rem_hrs = summary.total_rem_sleep_time_milli / 3600000 awake_hrs = summary.total_awake_time_milli / 3600000 print(f" Sleep Stages:") print(f" Light: {light_hrs:.1f}h") print(f" Deep: {deep_hrs:.1f}h") print(f" REM: {rem_hrs:.1f}h") print(f" Awake: {awake_hrs:.1f}h") print(f" Sleep Cycles: {summary.sleep_cycle_count}") print(f" Disturbances: {summary.disturbance_count}") print(f" Efficiency: {summary.sleep_efficiency_percentage:.1f}%") if sleep.score: print(f" Performance: {sleep.score.sleep_performance_percentage:.1f}%" if sleep.score.sleep_performance_percentage else "") print(f" Respiratory Rate: {sleep.score.respiratory_rate:.1f} bpm" if sleep.score.respiratory_rate else "") print() ``` -------------------------------- ### Get Individual Cycle by ID Source: https://context7.com/felixnext/whoopy/llms.txt Retrieve a specific cycle's data using its unique ID. This includes basic cycle information and associated sleep data. ```APIDOC ## Get Individual Cycle by ID ### Description Retrieve a specific cycle's data using its unique ID. This includes basic cycle information and associated sleep data. ### Method GET ### Endpoint `/cycles/{cycle_id}` ### Parameters #### Path Parameters - **cycle_id** (integer) - Required - The unique identifier for the cycle. ### Request Example ```python from whoopy import WhoopClient from whoopy.exceptions import ResourceNotFoundError client = WhoopClient.from_config() with client: try: # Get specific cycle cycle = client.cycles.get_by_id(12345) print(f"Cycle {cycle.id}") print(f"User ID: {cycle.user_id}") print(f"State: {cycle.score_state}") print(f"Timezone: {cycle.timezone_offset}") # Get sleep associated with this cycle sleep = client.cycles.get_sleep(cycle.id) print(f"Sleep duration: {sleep.duration_hours:.1f} hours") except ResourceNotFoundError as e: print(f"Cycle not found: {e}") ``` ### Response #### Success Response (200) - **id** (integer) - The cycle's unique identifier. - **user_id** (integer) - The user's unique identifier. - **score_state** (string) - The state of the cycle's score. - **timezone_offset** (integer) - The timezone offset for the cycle. - **sleep** (object) - Associated sleep data (details depend on the sleep endpoint). #### Response Example ```json { "id": 12345, "user_id": 67890, "score_state": "READY", "timezone_offset": -28800, "sleep": { "id": "abcde-12345", "duration_hours": 7.5 } } ``` ``` -------------------------------- ### Get Individual Cycle by ID with Whoopy API Source: https://context7.com/felixnext/whoopy/llms.txt This snippet demonstrates how to fetch a specific cycle's data using its ID from the Whoopy API. It also shows how to retrieve associated sleep data for that cycle. It requires the `whoopy` library and handles `ResourceNotFoundError` for invalid IDs. ```python from whoopy import WhoopClient from whoopy.exceptions import ResourceNotFoundError client = WhoopClient.from_config() with client: try: # Get specific cycle cycle = client.cycles.get_by_id(12345) print(f"Cycle {cycle.id}") print(f"User ID: {cycle.user_id}") print(f"State: {cycle.score_state}") print(f"Timezone: {cycle.timezone_offset}") # Get sleep associated with this cycle sleep = client.cycles.get_sleep(cycle.id) print(f"Sleep duration: {sleep.duration_hours:.1f} hours") except ResourceNotFoundError as e: print(f"Cycle not found: {e}") ``` -------------------------------- ### Get Recovery Metrics for Cycles using Whoopy Source: https://context7.com/felixnext/whoopy/llms.txt Retrieves recovery data for recent Whoop cycles. It iterates through cycles, fetches recovery details for each, and prints metrics like recovery score, resting heart rate, HRV, and skin temperature. Handles cases where recovery data might be missing for a cycle. ```python from whoopy import WhoopClient from whoopy.exceptions import ResourceNotFoundError from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get recent cycles cycles = client.cycles.get_all( start=datetime.now() - timedelta(days=7), limit_per_page=10 ) # Get recovery for each cycle for cycle in cycles: try: recovery = client.recovery.get_for_cycle(cycle.id) print(f"\nRecovery for Cycle {cycle.id}:") print(f" Date: {recovery.created_at}") if recovery.score: print(f" Recovery Score: {recovery.score.recovery_score}%") print(f" Resting HR: {recovery.score.resting_heart_rate} bpm") print(f" HRV (RMSSD): {recovery.score.hrv_rmssd_milli:.1f} ms") print(f" Skin Temp: {recovery.score.skin_temp_celsius:.1f}°C" if recovery.score.skin_temp_celsius else "") print(f" SpO2: {recovery.score.spo2_percentage:.1f}%" if recovery.score.spo2_percentage else "") print(f" State: {recovery.score_state}") except ResourceNotFoundError: print(f"No recovery data for cycle {cycle.id}") ``` -------------------------------- ### Get Sleep by ID and Export to DataFrame using Whoopy API Source: https://context7.com/felixnext/whoopy/llms.txt This snippet demonstrates retrieving a specific sleep activity by its ID and exporting sleep data for the last 30 days into a pandas DataFrame. It highlights how to access sleep performance and efficiency metrics and perform basic analysis like finding the best and worst sleep. It requires the `whoopy` and `pandas` libraries, along with `datetime` and `timedelta`. ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get specific sleep activity by UUID sleep = client.sleep.get_by_id("550e8400-e29b-41d4-a716-446655440000") print(f"Sleep score: {sleep.score.sleep_performance_percentage if sleep.score else 'N/A'}%") # Export sleep data to pandas DataFrame for analysis sleep_df = client.sleep.get_dataframe( start=datetime.now() - timedelta(days=30), limit_per_page=25 ) print(f"\nDataFrame shape: {sleep_df.shape}") print("\nSleep statistics:") print(sleep_df[['duration_hours', 'score.sleep_performance_percentage', 'score.sleep_efficiency_percentage']].describe()) # Find best and worst sleep if not sleep_df.empty and 'score.sleep_performance_percentage' in sleep_df.columns: best_sleep = sleep_df.loc[sleep_df['score.sleep_performance_percentage'].idxmax()] worst_sleep = sleep_df.loc[sleep_df['score.sleep_performance_percentage'].idxmin()] print(f"\nBest sleep: {best_sleep['score.sleep_performance_percentage']:.1f}%") print(f"Worst sleep: {worst_sleep['score.sleep_performance_percentage']:.1f}%") ``` -------------------------------- ### Initialize and Authorize Whoopy Client in Python Source: https://github.com/felixnext/whoopy/blob/main/tools/playground.ipynb This snippet shows how to import necessary libraries, set up paths, and initialize the WhoopClient using token or OAuth flow. It demonstrates loading configuration and token files, and performing an initial user profile retrieval. ```python import os import sys from pathlib import Path import whoopy from whoopy import WhoopClient # include parent path CUR_DIR = Path(os.getcwd()) sys.path.insert(0, str(CUR_DIR / "..")) print(whoopy.__version__) # create few variables TOKEN = CUR_DIR / ".tokens" / "token.json" CONFIG = CUR_DIR / ".." / "config.json" # init client client = WhoopClient.from_token_or_flow(CONFIG, TOKEN) client.user.profile() ``` -------------------------------- ### Development Workflow Steps (Bash) Source: https://github.com/felixnext/whoopy/blob/main/readme.md Steps for contributing to the Whoopy project, including forking, creating branches, making changes, running tests and linting, committing, and pushing code. This outlines a standard Git-based development workflow. ```bash 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Make your changes and add tests 4. Run tests and linting (`uv run pytest && uv run ruff check`) 5. Commit your changes (`git commit -m 'Add amazing feature'`) 6. Push to the branch (`git push origin feature/amazing-feature`) 7. Open a Pull Request ``` -------------------------------- ### Initialize WhoopClient from Configuration and Token Files Source: https://context7.com/felixnext/whoopy/llms.txt Initializes the WhoopClient by loading configuration from a JSON file (containing client ID, secret, and redirect URI) and credentials from a token file. This method automatically handles token refreshing. The client is used within a context manager to access user profile and body measurements. ```python from whoopy import WhoopClient from datetime import datetime, timedelta # Create config.json with your credentials: # { # "client_id": "your_client_id", # "client_secret": "your_client_secret", # "redirect_uri": "http://localhost:1234" # } # Load client from config (handles token refresh automatically) client = WhoopClient.from_config( config_path="config.json", token_path=".whoop_credentials.json" ) with client: # Get user profile profile = client.user.get_profile() measurements = client.user.get_body_measurements() print(f"User: {profile.first_name} {profile.last_name}") print(f"Height: {measurements.height_meter:.2f}m") print(f"Weight: {measurements.weight_kilogram:.1f}kg") print(f"Max HR: {measurements.max_heart_rate} bpm") ``` -------------------------------- ### Configure Whoopy Client Source: https://github.com/felixnext/whoopy/blob/main/readme.md Creates a configuration file (config.json) with WHOOP API credentials such as client ID, client secret, and redirect URI. It also shows an alternative nested structure for backward compatibility. ```json { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "redirect_uri": "http://localhost:1234" } ``` ```json { "whoop": { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "redirect_uri": "http://localhost:1234" } } ``` -------------------------------- ### Whoopy Client Authentication Options Source: https://github.com/felixnext/whoopy/blob/main/readme.md Illustrates different methods for authenticating with the Whoopy API, including interactive OAuth flow, using existing tokens, and loading credentials from configuration files. It also shows how to save tokens. ```python # Option 1: Interactive OAuth flow (opens browser) client = WhoopClient.auth_flow( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", redirect_uri="http://localhost:1234" ) # Option 2: From existing token client = WhoopClient.from_token( access_token="YOUR_ACCESS_TOKEN", refresh_token="YOUR_REFRESH_TOKEN", client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET" ) # Option 3: From config files (recommended) client = WhoopClient.from_config() # Save credentials for later use client.save_token(".whoop_credentials.json") ``` -------------------------------- ### Initialize WhoopClient from Existing Access and Refresh Tokens Source: https://context7.com/felixnext/whoopy/llms.txt Initializes the WhoopClient using provided access token, refresh token, expiration time, scopes, client ID, and client secret. This is useful when you already have valid tokens and want to bypass the initial authentication flow. The client automatically refreshes the token when it expires and is used within a context manager to retrieve physiological cycles. ```python from whoopy import WhoopClient # Use existing access token and refresh token client = WhoopClient.from_token( access_token="your_access_token_here", refresh_token="your_refresh_token_here", expires_in=3600, scopes=["read:profile", "read:cycles", "read:sleep", "read:recovery", "read:workout"], client_id="your_client_id", client_secret="your_client_secret" ) with client: # Token will be automatically refreshed when expired cycles = client.cycles.get_all( start=datetime.now() - timedelta(days=7), end=datetime.now() ) print(f"Retrieved {len(cycles)} cycles") ``` -------------------------------- ### Initialize WhoopClient with OAuth2 Browser Flow Source: https://context7.com/felixnext/whoopy/llms.txt Initializes the WhoopClient using an interactive OAuth2 flow that opens a web browser for user authorization. It handles token saving and provides options for request delay and concurrent requests. The client is used within a context manager for proper resource handling. ```python from whoopy import WhoopClient # Interactive OAuth2 flow - opens browser for user authorization client = WhoopClient.auth_flow( client_id="your_client_id_here", client_secret="your_client_secret_here", redirect_uri="http://localhost:1234", open_browser=True, request_delay=0.2, # 200ms delay between requests max_concurrent_requests=3 ) # Save credentials for future use client.save_token(".whoop_credentials.json") # Use the client with client: profile = client.user.get_profile() print(f"Authenticated as: {profile.first_name} {profile.last_name}") ``` -------------------------------- ### Asynchronous Whoopy Client Usage Source: https://github.com/felixnext/whoopy/blob/main/readme.md Shows how to use the Whoopy client asynchronously for better performance, fetching user profile, cycles, and sleep data concurrently using asyncio. Requires API credentials to be configured. ```python import asyncio from whoopy import WhoopClientV2 async def main(): # Use async context manager async with WhoopClientV2.from_config() as client: # Fetch multiple data types concurrently profile, cycles, sleep = await asyncio.gather( client.user.get_profile(), client.cycles.get_all(limit_per_page=10), client.sleep.get_all(limit_per_page=10) ) print(f"User: {profile.first_name}") print(f"Recent cycles: {len(cycles)}") print(f"Recent sleep: {len(sleep)}") # Run the async function asyncio.run(main()) ``` -------------------------------- ### Code Quality Checks with Ruff and Mypy (Bash) Source: https://github.com/felixnext/whoopy/blob/main/readme.md Bash commands to perform code quality checks. Uses 'ruff' for linting and formatting, and 'mypy' for type checking. These tools help maintain code consistency and correctness. ```bash # Run linting uv run ruff check . # Format code uv run ruff format . # Type checking uv run mypy whoopy ``` -------------------------------- ### Synchronous Whoopy Client Usage Source: https://github.com/felixnext/whoopy/blob/main/readme.md Demonstrates how to use the Whoopy client synchronously to fetch user profile, recovery data, and sleep data, exporting sleep data to a pandas DataFrame. Requires API credentials to be configured. ```python from whoopy import WhoopClient from datetime import datetime, timedelta # Initialize client (loads credentials from config.json) client = WhoopClient.from_config() # Get user profile profile = client.user.get_profile() print(f"Hello, {profile.first_name}!") # Get recent recovery data recoveries = client.recovery.get_all( start=datetime.now() - timedelta(days=7), end=datetime.now() ) for recovery in recoveries: print(f"Recovery: {recovery.score.recovery_score}%") # Export to pandas DataFrame df = client.sleep.get_dataframe( start=datetime.now() - timedelta(days=30) ) print(df.describe()) ``` -------------------------------- ### Retrieve Recovery Data Collection as DataFrame in Python Source: https://github.com/felixnext/whoopy/blob/main/tools/playground.ipynb This snippet demonstrates how to retrieve the recovery data collection as a pandas DataFrame using the initialized WhoopClient. It assumes the client has already been successfully authorized. ```python client.recovery.collection_df() ``` -------------------------------- ### Python Error Handling for WHOOP API Source: https://context7.com/felixnext/whoopy/llms.txt Demonstrates comprehensive error handling for various WHOOP API exceptions including authentication, token expiration, rate limiting, resource not found, validation, and server errors. It utilizes the WhoopClient and standard Python try-except blocks to manage potential issues during data fetching. ```python from whoopy import WhoopClient from whoopy.exceptions import ( AuthenticationError, TokenExpiredError, RateLimitError, ResourceNotFoundError, ValidationError, ServerError, ConfigurationError ) from datetime import datetime, timedelta import time client = WhoopClient.from_config() with client: try: # Fetch data with comprehensive error handling cycles = client.cycles.get_all( start=datetime.now() - timedelta(days=30), limit_per_page=25 ) for cycle in cycles: try: recovery = client.recovery.get_for_cycle(cycle.id) print(f"Cycle {cycle.id}: Recovery {recovery.score.recovery_score}%") except ResourceNotFoundError: print(f"Cycle {cycle.id}: No recovery data") except AuthenticationError as e: print(f"Authentication failed: {e}") print("Please re-authenticate using auth_flow()") except TokenExpiredError as e: print(f"Token expired: {e}") # Token refresh is automatic, but you can handle it manually: client.refresh_token() client.save_token() except RateLimitError as e: print(f"Rate limit exceeded: {e}") if e.retry_after: print(f"Retry after {e.retry_after} seconds") time.sleep(e.retry_after) else: print("Consider increasing request_delay or reducing request frequency") except ValidationError as e: print(f"Invalid request parameters: {e}") print(f"Validation errors: {e.validation_errors}") except ServerError as e: print(f"Server error {e.status_code}: {e}") print("WHOOP API may be experiencing issues") except ConfigurationError as e: print(f"Configuration error: {e}") print("Check your config.json file") ``` -------------------------------- ### Python Request Throttling and Retries for WHOOP API Source: https://context7.com/felixnext/whoopy/llms.txt Configures request throttling and retry behavior for the WhoopClient using RetryConfig. This helps manage API rate limits and transient server errors by setting retry counts, delays, backoff factors, and specific HTTP status codes to retry on. Logging is enabled to observe retry attempts. ```python from whoopy import WhoopClient from whoopy.utils import RetryConfig import logging # Enable logging to see retry behavior logging.basicConfig(level=logging.INFO) # Configure retry behavior retry_config = RetryConfig( max_retries=5, retry_delay=1.0, backoff_factor=2.0, retry_on_statuses=[429, 500, 502, 503, 504] ) # Create client with throttling and retry configuration client = WhoopClient.from_config() # Alternative: create with custom settings from whoopy import WhoopClientV2Sync from whoopy.utils import TokenInfo token_info = TokenInfo( access_token="your_token", expires_in=3600, refresh_token="your_refresh_token", scopes=["read:profile", "read:cycles"] ) client = WhoopClientV2Sync( token_info=token_info, client_id="your_client_id", client_secret="your_client_secret", retry_config=retry_config, request_delay=0.5, # 500ms between requests max_concurrent_requests=5, # Max 5 concurrent requests auto_refresh_token=True ) with client: # Requests will be automatically throttled and retried cycles = client.cycles.get_all(limit_per_page=10) ``` -------------------------------- ### Accessing Sleep Data Source: https://context7.com/felixnext/whoopy/llms.txt Retrieve a list of sleep activities within a specified date range, including detailed metrics for each sleep session. ```APIDOC ## Accessing Sleep Data ### Get Sleep Activities with Detailed Metrics ### Description Retrieve a list of sleep activities within a specified date range, including detailed metrics for each sleep session. ### Method GET ### Endpoint `/sleep` ### Parameters #### Query Parameters - **start** (datetime) - Required - The start date for the query (YYYY-MM-DD). - **end** (datetime) - Required - The end date for the query (YYYY-MM-DD). - **limit_per_page** (integer) - Optional - The number of results to return per page (default 25). ### Request Example ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get sleep data from last 30 days sleep_activities = client.sleep.get_all( start=datetime.now() - timedelta(days=30), end=datetime.now(), limit_per_page=25 ) print(f"Found {len(sleep_activities)} sleep activities\n") for sleep in sleep_activities: print(f"Sleep ID: {sleep.id}") print(f" Date: {sleep.start}") print(f" Duration: {sleep.duration_hours:.1f} hours") print(f" Nap: {'Yes' if sleep.nap else 'No'}") print(f" Quality Duration: {sleep.quality_duration_hours:.1f} hours" if sleep.quality_duration_hours else "") print(f" Latency: {sleep.latency_hours:.1f} hours" if sleep.latency_hours else "") if sleep.score and sleep.score.stage_summary: summary = sleep.score.stage_summary # Convert milliseconds to hours for readability light_hrs = summary.total_light_sleep_time_milli / 3600000 deep_hrs = summary.total_slow_wave_sleep_time_milli / 3600000 rem_hrs = summary.total_rem_sleep_time_milli / 3600000 awake_hrs = summary.total_awake_time_milli / 3600000 print(f" Sleep Stages:") print(f" Light: {light_hrs:.1f}h") print(f" Deep: {deep_hrs:.1f}h") print(f" REM: {rem_hrs:.1f}h") print(f" Awake: {awake_hrs:.1f}h") print(f" Sleep Cycles: {summary.sleep_cycle_count}") print(f" Disturbances: {summary.disturbance_count}") print(f" Efficiency: {summary.sleep_efficiency_percentage:.1f}%") if sleep.score: print(f" Performance: {sleep.score.sleep_performance_percentage:.1f}%" if sleep.score.sleep_performance_percentage else "") print(f" Respiratory Rate: {sleep.score.respiratory_rate:.1f} bpm" if sleep.score.respiratory_rate else "") print() ``` ### Response #### Success Response (200) - **id** (string) - The unique identifier for the sleep activity. - **start** (datetime) - The start time of the sleep activity. - **duration_hours** (float) - The total duration of sleep in hours. - **nap** (boolean) - Indicates if the sleep was a nap. - **quality_duration_hours** (float) - The duration of quality sleep in hours. - **latency_hours** (float) - The time taken to fall asleep in hours. - **score** (object) - Object containing sleep score details. - **stage_summary** (object) - Summary of sleep stages. - **total_light_sleep_time_milli** (integer) - Total light sleep time in milliseconds. - **total_slow_wave_sleep_time_milli** (integer) - Total deep sleep time in milliseconds. - **total_rem_sleep_time_milli** (integer) - Total REM sleep time in milliseconds. - **total_awake_time_milli** (integer) - Total awake time in milliseconds. - **sleep_cycle_count** (integer) - Number of sleep cycles. - **disturbance_count** (integer) - Number of disturbances during sleep. - **sleep_efficiency_percentage** (float) - Percentage of time spent sleeping while in bed. - **sleep_performance_percentage** (float) - Overall sleep performance percentage. - **respiratory_rate** (float) - Average respiratory rate during sleep. #### Response Example ```json [ { "id": "abcde-12345", "start": "2023-10-26T23:00:00Z", "duration_hours": 7.5, "nap": false, "quality_duration_hours": 6.8, "latency_hours": 0.2, "score": { "stage_summary": { "total_light_sleep_time_milli": 7200000, "total_slow_wave_sleep_time_milli": 5400000, "total_rem_sleep_time_milli": 4500000, "total_awake_time_milli": 900000, "sleep_cycle_count": 4, "disturbance_count": 2, "sleep_efficiency_percentage": 85.0 }, "sleep_performance_percentage": 90.0, "respiratory_rate": 14.5 } } ] ``` ``` ```APIDOC ### Get Sleep by ID and Export to DataFrame ### Description Retrieve a specific sleep activity by its ID or export all sleep data within a date range to a pandas DataFrame for analysis. ### Method GET ### Endpoint `/sleep/{sleep_id}` (for specific sleep) or `/sleep` (for DataFrame) ### Parameters #### Path Parameters (for specific sleep) - **sleep_id** (string) - Required - The unique identifier (UUID) for the sleep activity. #### Query Parameters (for DataFrame) - **start** (datetime) - Required - The start date for the query (YYYY-MM-DD). - **end** (datetime) - Optional - The end date for the query (YYYY-MM-DD). - **limit_per_page** (integer) - Optional - The number of results to return per page (default 25). ### Request Example ```python from whoopy import WhoopClient from datetime import datetime, timedelta client = WhoopClient.from_config() with client: # Get specific sleep activity by UUID sleep = client.sleep.get_by_id("550e8400-e29b-41d4-a716-446655440000") print(f"Sleep score: {sleep.score.sleep_performance_percentage if sleep.score else 'N/A'}%") # Export sleep data to pandas DataFrame for analysis sleep_df = client.sleep.get_dataframe( start=datetime.now() - timedelta(days=30), limit_per_page=25 ) print(f"\nDataFrame shape: {sleep_df.shape}") print("\nSleep statistics:") print(sleep_df[['duration_hours', 'score.sleep_performance_percentage', 'score.sleep_efficiency_percentage']].describe()) # Find best and worst sleep if not sleep_df.empty and 'score.sleep_performance_percentage' in sleep_df.columns: best_sleep = sleep_df.loc[sleep_df['score.sleep_performance_percentage'].idxmax()] worst_sleep = sleep_df.loc[sleep_df['score.sleep_performance_percentage'].idxmin()] print(f"\nBest sleep: {best_sleep['score.sleep_performance_percentage']:.1f}%") print(f"Worst sleep: {worst_sleep['score.sleep_performance_percentage']:.1f}%") ``` ### Response #### Success Response (200) - **sleep** (object) - Details of a specific sleep activity (same structure as in 'Get Sleep Activities'). - **sleep_df** (pandas.DataFrame) - A DataFrame containing sleep data, with columns like 'duration_hours', 'score.sleep_performance_percentage', etc. #### Response Example (DataFrame): ``` DataFrame shape: (30, 15) Sleep statistics: duration_hours score.sleep_performance_percentage score.sleep_efficiency_percentage count 30.000000 30.000000 30.000000 mean 7.210000 85.500000 91.200000 std 0.550000 5.800000 3.500000 min 6.100000 70.000000 80.000000 25% 6.800000 82.000000 89.500000 50% 7.300000 86.000000 92.000000 75% 7.600000 90.000000 94.000000 max 8.500000 95.000000 98.000000 ``` Best sleep: 95.0% Worst sleep: 70.0% ``` -------------------------------- ### Export Recovery Data to DataFrame using Whoopy and Pandas Source: https://context7.com/felixnext/whoopy/llms.txt Fetches recovery data for the past 30 days and exports it into a Pandas DataFrame. It then calculates correlations between key recovery metrics and performs a trend analysis using a 7-day rolling average for the recovery score. Requires Pandas library for DataFrame manipulation. ```python from whoopy import WhoopClient from datetime import datetime, timedelta import pandas as pd client = WhoopClient.from_config() with client: # Get all recovery data as DataFrame recovery_df = client.recovery.get_dataframe( start=datetime.now() - timedelta(days=30), limit_per_page=25 ) if not recovery_df.empty: print(f"Recovery data shape: {recovery_df.shape}\n") # Calculate correlations print("Recovery Metrics Correlations:") metrics = ['score.recovery_score', 'score.resting_heart_rate', 'score.hrv_rmssd_milli'] available_metrics = [m for m in metrics if m in recovery_df.columns] if available_metrics: correlations = recovery_df[available_metrics].corr() print(correlations) # Trend analysis recovery_df['date'] = pd.to_datetime(recovery_df['created_at']) recovery_df = recovery_df.sort_values('date') if 'score.recovery_score' in recovery_df.columns: print(f"\nAverage Recovery Score: {recovery_df['score.recovery_score'].mean():.1f}%") print(f"Recovery Trend (7-day rolling avg):") rolling_avg = recovery_df['score.recovery_score'].rolling(window=7).mean() print(rolling_avg.tail()) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.