# gunspec

Official Python SDK for the [GunSpec.io](https://gunspec.io) firearms specification database API.

## Installation

```bash
pip install gunspec
```

## Quick Start

```python
from gunspec import GunSpec

# Reads GUNSPEC_API_KEY from environment automatically
client = GunSpec()

# List firearms
result = client.firearms.list({"category": "pistol", "manufacturer": "glock"})
for firearm in result.data:
    print(firearm["name"], firearm["caliber"])

# Get a single firearm
result = client.firearms.get("glock-g17")
print(result.data["name"])
```

## Async Usage

```python
from gunspec import AsyncGunSpec

async with AsyncGunSpec() as client:
    result = await client.firearms.list({"category": "rifle"})
    for firearm in result.data:
        print(firearm["name"])
```

## Configuration

```python
from gunspec import GunSpec, RetryConfig

# Reads GUNSPEC_API_KEY from env automatically
client = GunSpec()

# Or configure explicitly
client = GunSpec(
    api_key="gs_...",                         # or set GUNSPEC_API_KEY env var
    base_url="https://api.gunspec.io",        # default
    timeout=30.0,                              # 30s default
    retry=RetryConfig(
        max_retries=2,                         # default
        initial_delay_s=0.5,                   # default
    ),
)
```

## Resources

| Resource | Methods |
|----------|---------|
| `client.firearms` | `list`, `get`, `search`, `compare`, `game_meta`, `action_types`, `filter_options`, `random`, `top`, `head_to_head`, `by_feature`, `by_action`, `by_material`, `by_designer`, `power_rating`, `timeline`, `by_conflict`, `get_variants`, `get_images`, `get_game_stats`, `get_dimensions`, `get_users`, `get_family_tree`, `get_similar`, `get_adoption_map`, `get_game_profile`, `get_silhouette`, `calculate`, `load`, `list_auto_paging` |
| `client.manufacturers` | `list`, `get`, `get_firearms`, `get_timeline`, `get_stats`, `list_auto_paging` |
| `client.calibers` | `list`, `get`, `compare`, `ballistics`, `get_firearms`, `get_parent_chain`, `get_family`, `get_ammunition`, `list_auto_paging` |
| `client.categories` | `list`, `get_firearms` |
| `client.stats` | `summary`, `production_status`, `field_coverage`, `popular_calibers`, `prolific_manufacturers`, `by_category`, `by_era`, `materials`, `adoption_by_country`, `adoption_by_type`, `action_types`, `feature_frequency`, `caliber_popularity_by_era` |
| `client.game` | `balance_report`, `tier_list`, `matchups`, `role_roster`, `stat_distribution` |
| `client.game_stats` | `list_versions`, `list_firearms`, `get_firearm` |
| `client.ammunition` | `list`, `get`, `get_bullet_svg`, `ballistics`, `list_auto_paging` |
| `client.countries` | `list`, `get_arsenal` |
| `client.conflicts` | `list` |
| `client.data_quality` | `coverage`, `confidence` |
| `client.favorites` | `list`, `add`, `remove` |
| `client.reports` | `create`, `list` |
| `client.support` | `create`, `list`, `get`, `reply` |
| `client.webhooks` | `list`, `create`, `get`, `update`, `delete`, `test` |
| `client.usage` | `get` |

## Auto-Pagination

```python
# Sync
for firearm in client.firearms.list_auto_paging({"category": "rifle"}):
    print(firearm["name"])

# Async
async for firearm in client.firearms.list_auto_paging({"category": "rifle"}):
    print(firearm["name"])
```

## Error Handling

```python
from gunspec import (
    GunSpec,
    NotFoundError,
    RateLimitError,
    AuthenticationError,
)

client = GunSpec()

try:
    result = client.firearms.get("nonexistent")
except NotFoundError as e:
    print(f"Not found: {e.message}")
    print(f"Request ID: {e.request_id}")
except RateLimitError as e:
    print(f"Retry after: {e.retry_after}s")
except AuthenticationError:
    print("Invalid API key")
```

## Context Managers

```python
# Sync
with GunSpec() as client:
    result = client.firearms.list()

# Async
async with AsyncGunSpec() as client:
    result = await client.firearms.list()
```

## Requirements

- Python >= 3.9
- httpx >= 0.25
- pydantic >= 2

## Publishing

```bash
cd packages/sdk-python

# Install build tools
pip install build twine

# Build sdist and wheel
python -m build

# Verify package
twine check dist/*

# Upload to PyPI
twine upload dist/*
```

For TestPyPI first:

```bash
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ gunspec
```

## Development

```bash
cd packages/sdk-python
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"

# Run tests
python -m pytest

# Lint
ruff check src/

# Type check
mypy src/gunspec/
```

## License

MIT
