swimmable-sdk


Nameswimmable-sdk JSON
Version 1.0.0 PyPI version JSON
download
home_pagehttps://github.com/swimmable/python-sdk
SummaryOfficial Python SDK for the Swimmable API - Real-time swimming conditions and water quality data
upload_time2025-07-29 13:33:49
maintainerNone
docs_urlNone
authorSwimmable
requires_python>=3.7
licenseNone
keywords swimming water quality weather api ocean beach lake safety conditions
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Swimmable Python SDK

[![PyPI version](https://badge.fury.io/py/swimmable-sdk.svg)](https://pypi.org/project/swimmable-sdk/)
[![Python](https://img.shields.io/pypi/pyversions/swimmable-sdk.svg)](https://pypi.org/project/swimmable-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Official Python SDK for the [Swimmable API](https://swimmable.app) - 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

```bash
pip install swimmable-sdk
```

```bash
poetry add swimmable-sdk
```

```bash
conda install -c conda-forge swimmable-sdk
```

## Quick Start

### Basic Usage (No API Key Required)

```python
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

```python
# 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)

```python
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

```python
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.

```python
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.

```python
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.

```python
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.

```python
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.

```python
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.

```python
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:

```python
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

```python
# 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

```python
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

```python
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

```python
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:

```python
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:

```python
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:

```python
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:

```python
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](https://swimmable.app/signup)
2. **Environment Variables**: Store your API key securely
   ```bash
   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:

```bash
# 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](CONTRIBUTING.md).

## Support

- 📧 **Email**: [developers@swimmable.app](mailto:developers@swimmable.app)
- 📖 **Documentation**: [swimmable.app/docs](https://swimmable.app/docs)
- 🐛 **Issues**: [GitHub Issues](https://github.com/swimmable/python-sdk/issues)
- 💬 **Community**: [Discord](https://discord.gg/swimmable)

## License

MIT License - see [LICENSE](LICENSE) file for details.

---

Built with ❤️ by the [Swimmable](https://swimmable.app) team. Making water activities safer worldwide! 🏊‍♀️🌊

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/swimmable/python-sdk",
    "name": "swimmable-sdk",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "swimming water quality weather API ocean beach lake safety conditions",
    "author": "Swimmable",
    "author_email": "developers@swimmable.app",
    "download_url": "https://files.pythonhosted.org/packages/6e/29/94abc41ae08d3b17967e7bbf20b663f8a053fa3fb7937b2815b7796040c3/swimmable_sdk-1.0.0.tar.gz",
    "platform": null,
    "description": "# Swimmable Python SDK\n\n[![PyPI version](https://badge.fury.io/py/swimmable-sdk.svg)](https://pypi.org/project/swimmable-sdk/)\n[![Python](https://img.shields.io/pypi/pyversions/swimmable-sdk.svg)](https://pypi.org/project/swimmable-sdk/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nOfficial Python SDK for the [Swimmable API](https://swimmable.app) - Get real-time swimming conditions, water quality data, and AI-powered safety scores for beaches, lakes, and pools worldwide.\n\n## Features\n\n- \ud83c\udfca **Real-time Swimming Conditions** - Water temperature, weather, and safety data\n- \ud83c\udf0a **Enhanced Analysis** - AI-powered swimmability scores and detailed breakdowns  \n- \ud83c\udfd6\ufe0f **Global Coverage** - 15,000+ beaches, lakes, and swimming spots worldwide\n- \ud83d\udd12 **Type Safe** - Full type hints with comprehensive dataclass definitions\n- \u26a1 **Modern** - Async/await support and clean Python APIs\n- \ud83d\ude80 **Lightweight** - Minimal dependencies, works with Python 3.7+\n- \ud83d\udcf1 **Cross-platform** - Works on Windows, macOS, Linux, and cloud platforms\n\n## Installation\n\n```bash\npip install swimmable-sdk\n```\n\n```bash\npoetry add swimmable-sdk\n```\n\n```bash\nconda install -c conda-forge swimmable-sdk\n```\n\n## Quick Start\n\n### Basic Usage (No API Key Required)\n\n```python\nfrom swimmable import SwimmableClient\n\nclient = SwimmableClient()\n\n# Get current swimming conditions for Santa Monica Beach\nconditions = client.get_conditions(lat=34.0195, lon=-118.4912)\n\nprint(f\"Water temperature: {conditions.water_temperature}\u00b0C\")\nprint(f\"Air temperature: {conditions.air_temperature}\u00b0C\")\nprint(f\"Weather: {conditions.weather_description}\")\n```\n\n### Enhanced Conditions with Safety Scores\n\n```python\n# Get detailed analysis with swimmability scoring\nenhanced = client.get_enhanced_conditions(lat=25.7617, lon=-80.1918)  # Miami Beach\n\nprint(f\"Swimmability Score: {enhanced.swimmability_score}/10\")\nprint(f\"Water Quality Score: {enhanced.subscores.water_quality}/10\")\nprint(f\"Safety Rating: {enhanced.subscores.surf_hazard}/10\")\n\n# Check for any safety warnings\nif enhanced.warnings:\n    print(\"\u26a0\ufe0f Safety Warnings:\", enhanced.warnings)\n```\n\n### With API Key (For Production Use)\n\n```python\nclient = SwimmableClient(api_key=\"your-api-key-here\")  # Get one at https://swimmable.app/signup\n\n# Now you can access premium features and higher rate limits\nstats = client.get_usage_stats()\nprint(f\"API calls this month: {stats.total_requests}\")\n```\n\n## API Reference\n\n### Client Configuration\n\n```python\nfrom swimmable import SwimmableClient, SwimmableConfig\n\n# Using configuration object\nconfig = SwimmableConfig(\n    api_key=\"your-api-key\",\n    base_url=\"https://api.swimmable.app\",  # Default\n    timeout=10.0,  # Default timeout in seconds\n    headers={\"Custom-Header\": \"value\"}\n)\nclient = SwimmableClient(config)\n\n# Or pass parameters directly\nclient = SwimmableClient(\n    api_key=\"your-api-key\",\n    timeout=15.0\n)\n```\n\n### Basic Methods\n\n#### `get_conditions(lat, lon)`\n\nGet basic swimming conditions for a location.\n\n```python\nconditions = client.get_conditions(lat=34.0522, lon=-118.2437)\n\n# Returns BasicConditions dataclass\nprint(f\"Air temperature: {conditions.air_temperature}\u00b0C\")\nprint(f\"Water temperature: {conditions.water_temperature}\u00b0C\")\nprint(f\"Weather: {conditions.weather_description}\")\nprint(f\"UV index: {conditions.uv_index}\")\nprint(f\"Wind speed: {conditions.wind_speed} km/h\")\nprint(f\"Wave height: {conditions.wave_height}m\")\nprint(f\"Timestamp: {conditions.timestamp}\")\n```\n\n#### `get_enhanced_conditions(lat, lon)`\n\nGet detailed analysis with AI-powered safety scores.\n\n```python\nenhanced = client.get_enhanced_conditions(lat=21.2765, lon=-157.8281)  # Waikiki Beach\n\nprint(f\"Swimmability Score: {enhanced.swimmability_score}/10\")\nprint(f\"Location: {enhanced.location.name}\")\nprint(f\"Timezone: {enhanced.location.timezone}\")\n\n# Detailed subscores\nprint(f\"Temperature Score: {enhanced.subscores.temperature}/10\")\nprint(f\"Water Quality Score: {enhanced.subscores.water_quality}/10\")\nprint(f\"Surf Hazard Score: {enhanced.subscores.surf_hazard}/10\")\nprint(f\"Weather Score: {enhanced.subscores.meteorology}/10\")\n\n# Water conditions\nwater = enhanced.conditions.water\nprint(f\"Water temp: {water.temperature.value}{water.temperature.unit}\")\nprint(f\"pH level: {water.ph}\")\nprint(f\"Bacteria status: {water.bacteria.status}\")\n\n# Ocean conditions\nocean = enhanced.conditions.ocean\nprint(f\"Wave height: {ocean.wave_height.value}{ocean.wave_height.unit}\")\nprint(f\"Rip current risk: {ocean.rip_risk}\")\n\n# Weather conditions\nweather = enhanced.conditions.weather\nprint(f\"Air temp: {weather.air_temp.value}{weather.air_temp.unit}\")\nprint(f\"Wind: {weather.wind_speed.value}{weather.wind_speed.unit} {weather.wind_direction}\")\n```\n\n#### `get_spots()`\n\nGet list of available swimming spots.\n\n```python\nspots = client.get_spots()\nprint(f\"Found {spots.count} swimming spots\")\n\nfor spot in spots.spots:\n    print(f\"{spot.name} - {spot.region}\")\n    print(f\"  Coordinates: {spot.lat}, {spot.lon}\")\n    print(f\"  Description: {spot.description}\")\n```\n\n### API Management (Requires API Key)\n\n#### `get_usage_stats(days=30)`\n\nGet your API usage statistics.\n\n```python\nstats = client.get_usage_stats(days=30)  # Last 30 days\nprint(f\"Total requests: {stats.total_requests}\")\nprint(f\"Successful requests: {stats.successful_requests}\")\nprint(f\"Error requests: {stats.error_requests}\")\nprint(f\"Average response time: {stats.avg_response_time}ms\")\n\nprint(\"Top endpoints:\")\nfor endpoint in stats.top_endpoints:\n    print(f\"  {endpoint.endpoint}: {endpoint.count} requests\")\n```\n\n#### `get_api_keys()`\n\nList your API keys.\n\n```python\nkeys = client.get_api_keys()\nfor key in keys:\n    status = \"Active\" if key.is_active else \"Inactive\"\n    print(f\"{key.name}: {status}\")\n    print(f\"  Prefix: {key.key_prefix}\")\n    print(f\"  Rate limit: {key.permissions.rate_limit}/hour\")\n    if key.expires_at:\n        print(f\"  Expires: {key.expires_at}\")\n```\n\n#### `create_api_key(key_data)`\n\nCreate a new API key.\n\n```python\nfrom swimmable import CreateApiKeyRequest\n\nrequest = CreateApiKeyRequest(\n    name=\"My App Key\",\n    description=\"API key for my swimming app\",\n    expires_in_days=365  # Optional expiration\n)\n\nresponse = client.create_api_key(request)\nprint(f\"New API key: {response.api_key}\")\n# \u26a0\ufe0f Save this key securely - you won't see it again!\n\nprint(f\"Key info: {response.api_key_record.name}\")\nprint(f\"Created: {response.api_key_record.created_at}\")\n```\n\n### Utility Functions\n\nThe SDK includes helpful utility functions:\n\n```python\nfrom swimmable.utils import LocationUtils, ConditionsUtils, ApiKeyUtils\n\n# Distance calculation\ndistance = LocationUtils.calculate_distance(\n    Coordinates(lat=34.0522, lon=-118.2437),  # Santa Monica\n    Coordinates(lat=25.7617, lon=-80.1918)   # Miami\n)\nprint(f\"Distance: {distance:.2f} km\")\n\n# Temperature conversion\nfahrenheit = ConditionsUtils.celsius_to_fahrenheit(25)\nprint(f\"25\u00b0C = {fahrenheit}\u00b0F\")\n\n# Safety assessment\nis_safe = ConditionsUtils.is_safe_for_swimming(enhanced_conditions)\nprint(\"\u2705 Safe to swim\" if is_safe else \"\u26a0\ufe0f Check conditions carefully\")\n\n# API key validation\nis_valid = ApiKeyUtils.validate_api_key(\"swm_1234567890abcdef...\")\nmasked_key = ApiKeyUtils.mask_api_key(\"swm_1234567890abcdef...\")\nprint(f\"Key valid: {is_valid}\")\nprint(f\"Masked key: {masked_key}\")\n```\n\n## Framework Examples\n\n### Django Integration\n\n```python\n# views.py\nfrom django.http import JsonResponse\nfrom swimmable import SwimmableClient\nfrom django.conf import settings\n\nclient = SwimmableClient(api_key=settings.SWIMMABLE_API_KEY)\n\ndef beach_conditions(request, lat, lon):\n    try:\n        conditions = client.get_conditions(lat=float(lat), lon=float(lon))\n        return JsonResponse({\n            'water_temperature': conditions.water_temperature,\n            'air_temperature': conditions.air_temperature,\n            'weather': conditions.weather_description,\n            'safe_to_swim': conditions.water_temperature > 18  # Basic safety check\n        })\n    except Exception as e:\n        return JsonResponse({'error': str(e)}, status=500)\n```\n\n### Flask API\n\n```python\nfrom flask import Flask, jsonify, request\nfrom swimmable import SwimmableClient\nimport os\n\napp = Flask(__name__)\nclient = SwimmableClient(api_key=os.getenv('SWIMMABLE_API_KEY'))\n\n@app.route('/api/conditions')\ndef get_conditions():\n    lat = float(request.args.get('lat'))\n    lon = float(request.args.get('lon'))\n    \n    try:\n        conditions = client.get_conditions(lat=lat, lon=lon)\n        return jsonify({\n            'water_temperature': conditions.water_temperature,\n            'air_temperature': conditions.air_temperature,\n            'weather_description': conditions.weather_description,\n            'uv_index': conditions.uv_index,\n            'timestamp': conditions.timestamp\n        })\n    except Exception as e:\n        return jsonify({'error': str(e)}), 500\n\nif __name__ == '__main__':\n    app.run(debug=True)\n```\n\n### FastAPI Integration\n\n```python\nfrom fastapi import FastAPI, HTTPException\nfrom swimmable import SwimmableClient, SwimmableError\nfrom pydantic import BaseModel\nimport os\n\napp = FastAPI()\nclient = SwimmableClient(api_key=os.getenv('SWIMMABLE_API_KEY'))\n\nclass LocationQuery(BaseModel):\n    lat: float\n    lon: float\n\n@app.get(\"/conditions\")\nasync def get_swimming_conditions(query: LocationQuery):\n    try:\n        conditions = client.get_conditions(lat=query.lat, lon=query.lon)\n        return {\n            \"water_temperature\": conditions.water_temperature,\n            \"air_temperature\": conditions.air_temperature,\n            \"weather_description\": conditions.weather_description,\n            \"safe_to_swim\": conditions.water_temperature > 18,\n            \"timestamp\": conditions.timestamp\n        }\n    except SwimmableError as e:\n        raise HTTPException(status_code=400, detail=str(e))\n```\n\n### Jupyter Notebook Analysis\n\n```python\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom swimmable import SwimmableClient\n\nclient = SwimmableClient()\n\n# Analyze conditions for multiple beaches\nbeaches = [\n    {\"name\": \"Santa Monica\", \"lat\": 34.0195, \"lon\": -118.4912},\n    {\"name\": \"Miami Beach\", \"lat\": 25.7617, \"lon\": -80.1918},\n    {\"name\": \"Waikiki\", \"lat\": 21.2765, \"lon\": -157.8281},\n]\n\ndata = []\nfor beach in beaches:\n    conditions = client.get_conditions(beach[\"lat\"], beach[\"lon\"])\n    data.append({\n        \"Beach\": beach[\"name\"],\n        \"Water Temp\": conditions.water_temperature,\n        \"Air Temp\": conditions.air_temperature,\n        \"Wave Height\": conditions.wave_height,\n        \"UV Index\": conditions.uv_index\n    })\n\ndf = pd.DataFrame(data)\nprint(df)\n\n# Plot water temperatures\nplt.figure(figsize=(10, 6))\nplt.bar(df[\"Beach\"], df[\"Water Temp\"])\nplt.title(\"Water Temperatures Across Beaches\")\nplt.ylabel(\"Temperature (\u00b0C)\")\nplt.show()\n```\n\n## Error Handling\n\nThe SDK provides specific exception types for different error scenarios:\n\n```python\nfrom swimmable import (\n    SwimmableClient, \n    SwimmableError, \n    SwimmableAPIError,\n    SwimmableTimeoutError,\n    SwimmableAuthenticationError,\n    SwimmableRateLimitError\n)\n\nclient = SwimmableClient(api_key=\"your-key\")\n\ntry:\n    conditions = client.get_conditions(lat=91, lon=0)  # Invalid latitude\nexcept SwimmableAuthenticationError as e:\n    print(f\"Authentication failed: {e}\")\nexcept SwimmableRateLimitError as e:\n    print(f\"Rate limit exceeded. Retry after {e.retry_after}s\")\nexcept SwimmableTimeoutError as e:\n    print(f\"Request timed out after {e.timeout}s\")\nexcept SwimmableAPIError as e:\n    print(f\"API error {e.status_code}: {e.message}\")\nexcept SwimmableError as e:\n    print(f\"General error: {e}\")\n```\n\n## Rate Limiting\n\nThe SDK includes built-in rate limiting utilities:\n\n```python\nfrom swimmable.utils import RateLimiter\n\nlimiter = RateLimiter(max_requests=100, window_seconds=60)  # 100 requests per minute\n\ndef make_safe_request(lat, lon):\n    if not limiter.can_make_request():\n        reset_time = limiter.get_reset_time()\n        raise Exception(f\"Rate limit exceeded. Try again in {reset_time:.1f}s\")\n    \n    conditions = client.get_conditions(lat=lat, lon=lon)\n    limiter.record_request()\n    \n    return conditions\n```\n\n## Type Hints and IDE Support\n\nThe SDK is fully typed and provides excellent IDE support:\n\n```python\nfrom swimmable import SwimmableClient, BasicConditions, EnhancedConditions\n\nclient: SwimmableClient = SwimmableClient(api_key=\"your-key\")\n\n# IDE will provide autocompletion and type checking\nconditions: BasicConditions = client.get_conditions(34.0522, -118.2437)\nenhanced: EnhancedConditions = client.get_enhanced_conditions(34.0522, -118.2437)\n\n# All dataclass fields are typed\nwater_temp: float = conditions.water_temperature\nscore: float = enhanced.swimmability_score\nlocation_name: str = enhanced.location.name\n```\n\n## Testing\n\nThe SDK is designed to be easily testable:\n\n```python\nimport pytest\nfrom unittest.mock import Mock, patch\nfrom swimmable import SwimmableClient, BasicConditions\n\ndef test_get_conditions():\n    client = SwimmableClient()\n    \n    # Mock the API response\n    mock_response = {\n        'airTemperature': 22.5,\n        'waterTemperature': 20.1,\n        'weatherDescription': 'sunny',\n        'uvIndex': 6.0,\n        'windSpeed': 15.2,\n        'waveHeight': 1.2,\n        'timestamp': '2024-01-15T10:30:00Z'\n    }\n    \n    with patch.object(client, '_make_request', return_value=mock_response):\n        conditions = client.get_conditions(34.0522, -118.2437)\n        \n        assert isinstance(conditions, BasicConditions)\n        assert conditions.water_temperature == 20.1\n        assert conditions.weather_description == 'sunny'\n```\n\n## API Key Management\n\n1. **Get an API Key**: Sign up at [swimmable.app/signup](https://swimmable.app/signup)\n2. **Environment Variables**: Store your API key securely\n   ```bash\n   export SWIMMABLE_API_KEY=your-api-key-here\n   ```\n3. **Rate Limits**: Free tier includes generous limits, paid plans available\n4. **Security**: Never expose API keys in source code or logs\n\n## Development\n\nTo contribute to the SDK:\n\n```bash\n# Clone the repository\ngit clone https://github.com/swimmable/python-sdk\ncd python-sdk\n\n# Install in development mode\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Run type checking\nmypy src/swimmable\n\n# Format code\nblack src/ tests/\nisort src/ tests/\n```\n\n## Changelog\n\n### v1.0.0\n- Initial release with full API coverage\n- Complete type hints and dataclass support\n- Comprehensive error handling\n- Rate limiting utilities\n- Framework integration examples\n\n## Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md).\n\n## Support\n\n- \ud83d\udce7 **Email**: [developers@swimmable.app](mailto:developers@swimmable.app)\n- \ud83d\udcd6 **Documentation**: [swimmable.app/docs](https://swimmable.app/docs)\n- \ud83d\udc1b **Issues**: [GitHub Issues](https://github.com/swimmable/python-sdk/issues)\n- \ud83d\udcac **Community**: [Discord](https://discord.gg/swimmable)\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n---\n\nBuilt with \u2764\ufe0f by the [Swimmable](https://swimmable.app) team. Making water activities safer worldwide! \ud83c\udfca\u200d\u2640\ufe0f\ud83c\udf0a\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Official Python SDK for the Swimmable API - Real-time swimming conditions and water quality data",
    "version": "1.0.0",
    "project_urls": {
        "Documentation": "https://swimmable.app/docs",
        "Homepage": "https://swimmable.app",
        "Source": "https://github.com/swimmable/python-sdk",
        "Tracker": "https://github.com/swimmable/python-sdk/issues"
    },
    "split_keywords": [
        "swimming",
        "water",
        "quality",
        "weather",
        "api",
        "ocean",
        "beach",
        "lake",
        "safety",
        "conditions"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f8f68a941fae291c661e400cbabcdda0147062c1b68d6f0ba4217d698984c048",
                "md5": "7310ce2c4e67363c3e6946bfaf48b417",
                "sha256": "2ea3fcd1d0c6f869ea7b464bf79b7519440ff0a5bd71d2635056913902373ada"
            },
            "downloads": -1,
            "filename": "swimmable_sdk-1.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7310ce2c4e67363c3e6946bfaf48b417",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 18696,
            "upload_time": "2025-07-29T13:33:47",
            "upload_time_iso_8601": "2025-07-29T13:33:47.683134Z",
            "url": "https://files.pythonhosted.org/packages/f8/f6/8a941fae291c661e400cbabcdda0147062c1b68d6f0ba4217d698984c048/swimmable_sdk-1.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6e2994abc41ae08d3b17967e7bbf20b663f8a053fa3fb7937b2815b7796040c3",
                "md5": "6fdb29259291967a664abf34c4d52c6e",
                "sha256": "ab684794617af2310036eb9a70c18241c215ce4c7de39bbddf0739bb98db257d"
            },
            "downloads": -1,
            "filename": "swimmable_sdk-1.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "6fdb29259291967a664abf34c4d52c6e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 23296,
            "upload_time": "2025-07-29T13:33:49",
            "upload_time_iso_8601": "2025-07-29T13:33:49.122328Z",
            "url": "https://files.pythonhosted.org/packages/6e/29/94abc41ae08d3b17967e7bbf20b663f8a053fa3fb7937b2815b7796040c3/swimmable_sdk-1.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-29 13:33:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "swimmable",
    "github_project": "python-sdk",
    "github_not_found": true,
    "lcname": "swimmable-sdk"
}
        
Elapsed time: 0.96966s