Metadata-Version: 2.4
Name: birdlife-ebird-iucn
Version: 0.2.1
Summary: Synthesize eBird observation data with IUCN Red List conservation status
Project-URL: Homepage, https://github.com/birdlife-tools/ebird-iucn-synthesizer
Project-URL: Documentation, https://github.com/birdlife-tools/ebird-iucn-synthesizer#readme
Project-URL: Repository, https://github.com/birdlife-tools/ebird-iucn-synthesizer
Project-URL: Issues, https://github.com/birdlife-tools/ebird-iucn-synthesizer/issues
Author-email: BirdLife Tools <info@birdlife.tech>
License-Expression: MIT
License-File: LICENSE
Keywords: biodiversity,birds,conservation,ebird,iucn
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.10
Requires-Dist: fastavro>=1.9
Requires-Dist: httpx>=0.25
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: pydantic>=2.0
Provides-Extra: dev
Requires-Dist: jsonschema>=4.0; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
Description-Content-Type: text/markdown

# eBird-IUCN Synthesizer

CLI tool and Python library that synthesizes eBird observation data with IUCN Red List conservation status.

## Problem

Ecologists spend hours manually cross-referencing bird sighting data when preparing conservation reports. eBird provides observation data, IUCN Red List provides threat categories — but these databases don't communicate automatically.

## Solution

Query eBird for a region or coordinates, automatically enrich with IUCN threat status, and export clean JSON/CSV/Avro reports ready for analysis.

## Features

- Query by region code (e.g., `RS`, `US-NY`) or coordinates
- IUCN Red List enrichment with local caching (90-day TTL)
- Filter to threatened species only (VU/EN/CR)
- Multiple output formats: JSON, CSV, Avro
- Optional UUID resolution via BirdLife Resolution API
- Stale-while-revalidate caching strategy
- Cache backends: JSON files, SQLite, PostgreSQL

## Installation

```bash
pip install birdlife-ebird-iucn

# With PostgreSQL support
pip install birdlife-ebird-iucn[postgres]
```

## Quick Start

### CLI

```bash
# Set up credentials
export EBIRD_API_KEY="your-key"      # https://ebird.org/api/keygen
export IUCN_API_TOKEN="your-token"   # https://api.iucnredlist.org/users/sign_up

# Query by region
python -m birdlife_ebird_iucn RS --format json

# Query by coordinates
python -m birdlife_ebird_iucn --lat 44.8 --lng 20.4 --days 7

# Threatened species only
python -m birdlife_ebird_iucn RS --threatened-only --format csv
```

### Python API

```python
import asyncio
from birdlife_ebird_iucn import Config, Synthesizer
from birdlife_ebird_iucn.serializers import JsonSerializer

async def main():
    config = Config()  # Reads from environment
    synth = Synthesizer.from_config(config)
    
    try:
        result = await synth.synthesize(
            region_code="RS",
            back_days=14,
            threatened_only=True,
        )
        
        # Access species via result.data, location via result.meta.location
        print(f"Found {len(result.data)} threatened species")
        for species in result.data:
            print(f"  {species.iucn_status.value}: {species.scientific_name}")
        
        # Export to JSON
        print(JsonSerializer().serialize(result))
    finally:
        await synth.close()

asyncio.run(main())
```

## Configuration

All settings via environment variables or `.env` file:

| Variable | Required | Description |
|----------|----------|-------------|
| `EBIRD_API_KEY` | Yes | eBird API key |
| `IUCN_API_TOKEN` | Yes | IUCN Red List API token |
| `CACHE_TYPE` | No | `json` (default), `sqlite`, or `postgres` |
| `CACHE_DIR` | No | Cache directory (default: `./.cache`) |
| `CACHE_TTL_DAYS` | No | Cache TTL in days (default: `90`) |
| `POSTGRES_URL` | If postgres | PostgreSQL connection URL |
| `RESOLUTION_API_URL` | No | BirdLife Resolution API for canonical UUIDs |
| `RESOLUTION_API_TOKEN` | No | Bearer token for Resolution API |

## Cache Backends

### JSON (default)
```bash
CACHE_TYPE=json
CACHE_DIR=./.cache
```

### SQLite
```bash
CACHE_TYPE=sqlite
CACHE_DIR=./.cache
```

### PostgreSQL
```bash
CACHE_TYPE=postgres
POSTGRES_URL=postgresql://user:pass@localhost:5432/birdlife
```

## Resolution API

By default, UUIDs are generated locally. To use canonical BirdLife IDs:

```bash
RESOLUTION_API_URL=https://birdlife.tech/api/v1
```

## Output Formats

All outputs follow the **API Response Convention** with a `{data, meta}` envelope:

```json
{
  "data": [...],   // Taxon[] - species found
  "meta": {
    "resultType": "species-search",
    "queryTimestamp": "2026-07-10T12:00:00Z",
    "filtersApplied": {"backDays": "14", "threatenedOnly": "true"},
    "location": {
      "locationID": "...",
      "name": "Serbia",
      "decimalLatitude": 44.0,
      "decimalLongitude": 21.0,
      ...
    }
  }
}
```

### JSON
Schema-compliant JSON following [birdlife-schema](https://github.com/birdlife-tools/birdlife-schema).

### CSV
Flattened tabular format for spreadsheet analysis. Metadata fields extracted from `meta`.

### Avro
Binary format for big data pipelines.

## Examples

The `examples/` directory contains ready-to-run examples:

### CLI Example

```bash
cd examples
cp .env.example .env  # Add your API keys

# Query Serbia
python cli_example.py RS

# Query by coordinates (Belgrade)
python cli_example.py --lat 44.8 --lng 20.4 --days 7

# Threatened species only, CSV output
python cli_example.py RS --threatened-only --format csv
```

### Jupyter Notebook

Interactive notebook with step-by-step examples:

```bash
cd examples
jupyter notebook notebook_example.ipynb
```

### Region Codes

eBird uses hierarchical region codes:
- Country: `RS` (Serbia), `US` (USA), `GB` (UK)
- State/Province: `US-NY` (New York), `CA-ON` (Ontario)
- County: `US-NY-061` (New York County)

Find codes at: https://ebird.org/region/world

## Development

```bash
# Clone and install
git clone https://github.com/birdlife-tools/ebird-iucn-synthesizer
cd ebird-iucn-synthesizer
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest

# Type check
mypy src/

# Lint
ruff check src/
```

## Architecture

```
synthesize() request
       │
       ▼
┌──────────────┐
│  eBird API   │ ─── recent observations
└──────────────┘
       │
       ▼
┌──────────────┐
│  IUCN Cache  │ ─── threat status (stale-while-revalidate)
└──────────────┘
       │
       ▼
┌──────────────┐
│  Resolver    │ ─── canonical UUIDs (optional)
└──────────────┘
       │
       ▼
┌──────────────┐
│  Serializer  │ ─── JSON / CSV / Avro
└──────────────┘
```

## Community

Join the discussion:

[![Matrix](https://img.shields.io/badge/Matrix-Chat-black?logo=matrix)](https://matrix.to/#/#ebird-iucn-synthesizer:matrix.org)

## License

MIT — see [LICENSE](LICENSE)
