Skip to main content

Official Python SDK for the Swimmable API - Real-time swimming conditions and water quality data

Project description

Swimmable Python SDK

PyPI version Python License: MIT

Official Python SDK for the Swimmable API - Get real-time swimming conditions, water quality data, and AI-powered safety scores for beaches, lakes, and pools worldwide.

Features

  • 🏊 Real-time Swimming Conditions - Water temperature, weather, and safety data
  • 🌊 Enhanced Analysis - AI-powered swimmability scores and detailed breakdowns
  • 🏖️ Global Coverage - 15,000+ beaches, lakes, and swimming spots worldwide
  • 🔒 Type Safe - Full type hints with comprehensive dataclass definitions
  • Modern - Async/await support and clean Python APIs
  • 🚀 Lightweight - Minimal dependencies, works with Python 3.7+
  • 📱 Cross-platform - Works on Windows, macOS, Linux, and cloud platforms

Installation

pip install swimmable-sdk
poetry add swimmable-sdk
conda install -c conda-forge swimmable-sdk

Quick Start

Basic Usage (No API Key Required)

from swimmable import SwimmableClient

client = SwimmableClient()

# Get current swimming conditions for Santa Monica Beach
conditions = client.get_conditions(lat=34.0195, lon=-118.4912)

print(f"Water temperature: {conditions.water_temperature}°C")
print(f"Air temperature: {conditions.air_temperature}°C")
print(f"Weather: {conditions.weather_description}")

Enhanced Conditions with Safety Scores

# Get detailed analysis with swimmability scoring
enhanced = client.get_enhanced_conditions(lat=25.7617, lon=-80.1918)  # Miami Beach

print(f"Swimmability Score: {enhanced.swimmability_score}/10")
print(f"Water Quality Score: {enhanced.subscores.water_quality}/10")
print(f"Safety Rating: {enhanced.subscores.surf_hazard}/10")

# Check for any safety warnings
if enhanced.warnings:
    print("⚠️ Safety Warnings:", enhanced.warnings)

With API Key (For Production Use)

client = SwimmableClient(api_key="your-api-key-here")  # Get one at https://swimmable.app/signup

# Now you can access premium features and higher rate limits
stats = client.get_usage_stats()
print(f"API calls this month: {stats.total_requests}")

API Reference

Client Configuration

from swimmable import SwimmableClient, SwimmableConfig

# Using configuration object
config = SwimmableConfig(
    api_key="your-api-key",
    base_url="https://api.swimmable.app",  # Default
    timeout=10.0,  # Default timeout in seconds
    headers={"Custom-Header": "value"}
)
client = SwimmableClient(config)

# Or pass parameters directly
client = SwimmableClient(
    api_key="your-api-key",
    timeout=15.0
)

Basic Methods

get_conditions(lat, lon)

Get basic swimming conditions for a location.

conditions = client.get_conditions(lat=34.0522, lon=-118.2437)

# Returns BasicConditions dataclass
print(f"Air temperature: {conditions.air_temperature}°C")
print(f"Water temperature: {conditions.water_temperature}°C")
print(f"Weather: {conditions.weather_description}")
print(f"UV index: {conditions.uv_index}")
print(f"Wind speed: {conditions.wind_speed} km/h")
print(f"Wave height: {conditions.wave_height}m")
print(f"Timestamp: {conditions.timestamp}")

get_enhanced_conditions(lat, lon)

Get detailed analysis with AI-powered safety scores.

enhanced = client.get_enhanced_conditions(lat=21.2765, lon=-157.8281)  # Waikiki Beach

print(f"Swimmability Score: {enhanced.swimmability_score}/10")
print(f"Location: {enhanced.location.name}")
print(f"Timezone: {enhanced.location.timezone}")

# Detailed subscores
print(f"Temperature Score: {enhanced.subscores.temperature}/10")
print(f"Water Quality Score: {enhanced.subscores.water_quality}/10")
print(f"Surf Hazard Score: {enhanced.subscores.surf_hazard}/10")
print(f"Weather Score: {enhanced.subscores.meteorology}/10")

# Water conditions
water = enhanced.conditions.water
print(f"Water temp: {water.temperature.value}{water.temperature.unit}")
print(f"pH level: {water.ph}")
print(f"Bacteria status: {water.bacteria.status}")

# Ocean conditions
ocean = enhanced.conditions.ocean
print(f"Wave height: {ocean.wave_height.value}{ocean.wave_height.unit}")
print(f"Rip current risk: {ocean.rip_risk}")

# Weather conditions
weather = enhanced.conditions.weather
print(f"Air temp: {weather.air_temp.value}{weather.air_temp.unit}")
print(f"Wind: {weather.wind_speed.value}{weather.wind_speed.unit} {weather.wind_direction}")

get_spots()

Get list of available swimming spots.

spots = client.get_spots()
print(f"Found {spots.count} swimming spots")

for spot in spots.spots:
    print(f"{spot.name} - {spot.region}")
    print(f"  Coordinates: {spot.lat}, {spot.lon}")
    print(f"  Description: {spot.description}")

API Management (Requires API Key)

get_usage_stats(days=30)

Get your API usage statistics.

stats = client.get_usage_stats(days=30)  # Last 30 days
print(f"Total requests: {stats.total_requests}")
print(f"Successful requests: {stats.successful_requests}")
print(f"Error requests: {stats.error_requests}")
print(f"Average response time: {stats.avg_response_time}ms")

print("Top endpoints:")
for endpoint in stats.top_endpoints:
    print(f"  {endpoint.endpoint}: {endpoint.count} requests")

get_api_keys()

List your API keys.

keys = client.get_api_keys()
for key in keys:
    status = "Active" if key.is_active else "Inactive"
    print(f"{key.name}: {status}")
    print(f"  Prefix: {key.key_prefix}")
    print(f"  Rate limit: {key.permissions.rate_limit}/hour")
    if key.expires_at:
        print(f"  Expires: {key.expires_at}")

create_api_key(key_data)

Create a new API key.

from swimmable import CreateApiKeyRequest

request = CreateApiKeyRequest(
    name="My App Key",
    description="API key for my swimming app",
    expires_in_days=365  # Optional expiration
)

response = client.create_api_key(request)
print(f"New API key: {response.api_key}")
# ⚠️ Save this key securely - you won't see it again!

print(f"Key info: {response.api_key_record.name}")
print(f"Created: {response.api_key_record.created_at}")

Utility Functions

The SDK includes helpful utility functions:

from swimmable.utils import LocationUtils, ConditionsUtils, ApiKeyUtils

# Distance calculation
distance = LocationUtils.calculate_distance(
    Coordinates(lat=34.0522, lon=-118.2437),  # Santa Monica
    Coordinates(lat=25.7617, lon=-80.1918)   # Miami
)
print(f"Distance: {distance:.2f} km")

# Temperature conversion
fahrenheit = ConditionsUtils.celsius_to_fahrenheit(25)
print(f"25°C = {fahrenheit}°F")

# Safety assessment
is_safe = ConditionsUtils.is_safe_for_swimming(enhanced_conditions)
print("✅ Safe to swim" if is_safe else "⚠️ Check conditions carefully")

# API key validation
is_valid = ApiKeyUtils.validate_api_key("swm_1234567890abcdef...")
masked_key = ApiKeyUtils.mask_api_key("swm_1234567890abcdef...")
print(f"Key valid: {is_valid}")
print(f"Masked key: {masked_key}")

Framework Examples

Django Integration

# views.py
from django.http import JsonResponse
from swimmable import SwimmableClient
from django.conf import settings

client = SwimmableClient(api_key=settings.SWIMMABLE_API_KEY)

def beach_conditions(request, lat, lon):
    try:
        conditions = client.get_conditions(lat=float(lat), lon=float(lon))
        return JsonResponse({
            'water_temperature': conditions.water_temperature,
            'air_temperature': conditions.air_temperature,
            'weather': conditions.weather_description,
            'safe_to_swim': conditions.water_temperature > 18  # Basic safety check
        })
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

Flask API

from flask import Flask, jsonify, request
from swimmable import SwimmableClient
import os

app = Flask(__name__)
client = SwimmableClient(api_key=os.getenv('SWIMMABLE_API_KEY'))

@app.route('/api/conditions')
def get_conditions():
    lat = float(request.args.get('lat'))
    lon = float(request.args.get('lon'))
    
    try:
        conditions = client.get_conditions(lat=lat, lon=lon)
        return jsonify({
            'water_temperature': conditions.water_temperature,
            'air_temperature': conditions.air_temperature,
            'weather_description': conditions.weather_description,
            'uv_index': conditions.uv_index,
            'timestamp': conditions.timestamp
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)

FastAPI Integration

from fastapi import FastAPI, HTTPException
from swimmable import SwimmableClient, SwimmableError
from pydantic import BaseModel
import os

app = FastAPI()
client = SwimmableClient(api_key=os.getenv('SWIMMABLE_API_KEY'))

class LocationQuery(BaseModel):
    lat: float
    lon: float

@app.get("/conditions")
async def get_swimming_conditions(query: LocationQuery):
    try:
        conditions = client.get_conditions(lat=query.lat, lon=query.lon)
        return {
            "water_temperature": conditions.water_temperature,
            "air_temperature": conditions.air_temperature,
            "weather_description": conditions.weather_description,
            "safe_to_swim": conditions.water_temperature > 18,
            "timestamp": conditions.timestamp
        }
    except SwimmableError as e:
        raise HTTPException(status_code=400, detail=str(e))

Jupyter Notebook Analysis

import matplotlib.pyplot as plt
import pandas as pd
from swimmable import SwimmableClient

client = SwimmableClient()

# Analyze conditions for multiple beaches
beaches = [
    {"name": "Santa Monica", "lat": 34.0195, "lon": -118.4912},
    {"name": "Miami Beach", "lat": 25.7617, "lon": -80.1918},
    {"name": "Waikiki", "lat": 21.2765, "lon": -157.8281},
]

data = []
for beach in beaches:
    conditions = client.get_conditions(beach["lat"], beach["lon"])
    data.append({
        "Beach": beach["name"],
        "Water Temp": conditions.water_temperature,
        "Air Temp": conditions.air_temperature,
        "Wave Height": conditions.wave_height,
        "UV Index": conditions.uv_index
    })

df = pd.DataFrame(data)
print(df)

# Plot water temperatures
plt.figure(figsize=(10, 6))
plt.bar(df["Beach"], df["Water Temp"])
plt.title("Water Temperatures Across Beaches")
plt.ylabel("Temperature (°C)")
plt.show()

Error Handling

The SDK provides specific exception types for different error scenarios:

from swimmable import (
    SwimmableClient, 
    SwimmableError, 
    SwimmableAPIError,
    SwimmableTimeoutError,
    SwimmableAuthenticationError,
    SwimmableRateLimitError
)

client = SwimmableClient(api_key="your-key")

try:
    conditions = client.get_conditions(lat=91, lon=0)  # Invalid latitude
except SwimmableAuthenticationError as e:
    print(f"Authentication failed: {e}")
except SwimmableRateLimitError as e:
    print(f"Rate limit exceeded. Retry after {e.retry_after}s")
except SwimmableTimeoutError as e:
    print(f"Request timed out after {e.timeout}s")
except SwimmableAPIError as e:
    print(f"API error {e.status_code}: {e.message}")
except SwimmableError as e:
    print(f"General error: {e}")

Rate Limiting

The SDK includes built-in rate limiting utilities:

from swimmable.utils import RateLimiter

limiter = RateLimiter(max_requests=100, window_seconds=60)  # 100 requests per minute

def make_safe_request(lat, lon):
    if not limiter.can_make_request():
        reset_time = limiter.get_reset_time()
        raise Exception(f"Rate limit exceeded. Try again in {reset_time:.1f}s")
    
    conditions = client.get_conditions(lat=lat, lon=lon)
    limiter.record_request()
    
    return conditions

Type Hints and IDE Support

The SDK is fully typed and provides excellent IDE support:

from swimmable import SwimmableClient, BasicConditions, EnhancedConditions

client: SwimmableClient = SwimmableClient(api_key="your-key")

# IDE will provide autocompletion and type checking
conditions: BasicConditions = client.get_conditions(34.0522, -118.2437)
enhanced: EnhancedConditions = client.get_enhanced_conditions(34.0522, -118.2437)

# All dataclass fields are typed
water_temp: float = conditions.water_temperature
score: float = enhanced.swimmability_score
location_name: str = enhanced.location.name

Testing

The SDK is designed to be easily testable:

import pytest
from unittest.mock import Mock, patch
from swimmable import SwimmableClient, BasicConditions

def test_get_conditions():
    client = SwimmableClient()
    
    # Mock the API response
    mock_response = {
        'airTemperature': 22.5,
        'waterTemperature': 20.1,
        'weatherDescription': 'sunny',
        'uvIndex': 6.0,
        'windSpeed': 15.2,
        'waveHeight': 1.2,
        'timestamp': '2024-01-15T10:30:00Z'
    }
    
    with patch.object(client, '_make_request', return_value=mock_response):
        conditions = client.get_conditions(34.0522, -118.2437)
        
        assert isinstance(conditions, BasicConditions)
        assert conditions.water_temperature == 20.1
        assert conditions.weather_description == 'sunny'

API Key Management

  1. Get an API Key: Sign up at swimmable.app/signup
  2. Environment Variables: Store your API key securely
    export SWIMMABLE_API_KEY=your-api-key-here
    
  3. Rate Limits: Free tier includes generous limits, paid plans available
  4. Security: Never expose API keys in source code or logs

Development

To contribute to the SDK:

# Clone the repository
git clone https://github.com/swimmable/python-sdk
cd python-sdk

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Run type checking
mypy src/swimmable

# Format code
black src/ tests/
isort src/ tests/

Changelog

v1.0.0

  • Initial release with full API coverage
  • Complete type hints and dataclass support
  • Comprehensive error handling
  • Rate limiting utilities
  • Framework integration examples

Contributing

We welcome contributions! Please see our Contributing Guide.

Support

License

MIT License - see LICENSE file for details.


Built with ❤️ by the Swimmable team. Making water activities safer worldwide! 🏊‍♀️🌊

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

swimmable_sdk-1.0.0.tar.gz (23.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

swimmable_sdk-1.0.0-py3-none-any.whl (18.7 kB view details)

Uploaded Python 3

File details

Details for the file swimmable_sdk-1.0.0.tar.gz.

File metadata

  • Download URL: swimmable_sdk-1.0.0.tar.gz
  • Upload date:
  • Size: 23.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for swimmable_sdk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ab684794617af2310036eb9a70c18241c215ce4c7de39bbddf0739bb98db257d
MD5 6fdb29259291967a664abf34c4d52c6e
BLAKE2b-256 6e2994abc41ae08d3b17967e7bbf20b663f8a053fa3fb7937b2815b7796040c3

See more details on using hashes here.

File details

Details for the file swimmable_sdk-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: swimmable_sdk-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 18.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for swimmable_sdk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2ea3fcd1d0c6f869ea7b464bf79b7519440ff0a5bd71d2635056913902373ada
MD5 7310ce2c4e67363c3e6946bfaf48b417
BLAKE2b-256 f8f68a941fae291c661e400cbabcdda0147062c1b68d6f0ba4217d698984c048

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page