Metadata-Version: 2.4
Name: nhtsa-recalls
Version: 0.1.0
Summary: A typed, tested Python client for NHTSA's vehicle recalls API
Project-URL: Homepage, https://github.com/thomaswcole1/nhtsa-recalls
Project-URL: Issues, https://github.com/thomaswcole1/nhtsa-recalls/issues
Author-email: Thomas Cole <thomaswcole1@gmail.com>
License-Expression: MIT
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
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 :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx<1.0,>=0.27
Requires-Dist: pandas>=2.0
Requires-Dist: pydantic<3.0,>=2.6
Provides-Extra: dev
Requires-Dist: mypy>=1.9; extra == 'dev'
Requires-Dist: pandas-stubs; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# nhtsa-recalls

A typed, tested Python client for [NHTSA's public vehicle recalls API](https://www.nhtsa.gov/nhtsa-datasets-and-apis#recalls). Query recalls by make, model, and model year, or by NHTSA campaign number, and get results back as a pandas `DataFrame`, ready for analysis.

## Features

- **DataFrame-native.** Recall lookups return a `pandas.DataFrame` directly — no manual parsing or conversion.
- **Validated responses.** Every record is validated against a typed schema before it reaches you; malformed individual records are skipped and logged rather than silently corrupting your data.
- **Resilient by default.** Automatic retries with exponential backoff on timeouts, connection errors, and rate limiting (HTTP 429) or transient server errors (5xx).
- **Clear errors.** A small, typed exception hierarchy distinguishes validation errors, HTTP errors, rate limiting, timeouts, and parse failures — so failures are loud and specific, not silent empty results.
- **No live calls in tests.** The test suite runs entirely against mocked HTTP responses.

## Installation

```bash
pip install nhtsa-recalls
```

Requires Python 3.10+.

## Quick start

```python
from nhtsa_recalls import RecallClient

with RecallClient() as client:
    df = client.get_by_vehicle(make="acura", model="rdx", model_year="2012")

print(df[["nhtsa_campaign_number", "component", "report_received_date"]])
```

## Usage

### Look up recalls by vehicle

```python
from nhtsa_recalls import RecallClient

with RecallClient() as client:
    df = client.get_by_vehicle(make="acura", model="rdx", model_year="2012")
```

At least one of `make`, `model`, or `model_year` is required; NHTSA accepts partial combinations, though results are most precise when all three are supplied.

### Look up a specific recall campaign

```python
with RecallClient() as client:
    df = client.get_by_campaign("19V182000")
```

### Discover valid makes, models, and model years

Useful for validating input or populating a UI before making a lookup:

```python
with RecallClient() as client:
    years = client.get_model_years()
    makes = client.get_makes(model_year="2021")
    models = client.get_models(model_year="2021", make="acura")
```

### Working with the result

`get_by_vehicle` and `get_by_campaign` return a standard `pandas.DataFrame`, with a stable, predictable column order and `report_received_date` as a proper `datetime64` column. From there, use pandas as usual:

```python
df.to_csv("recalls.csv", index=False)
df.to_parquet("recalls.parquet")
df.sort_values("report_received_date", ascending=False)
```

## Error handling

All exceptions raised by this package inherit from `nhtsa_recalls.NHTSAError`:

| Exception | Raised when |
|---|---|
| `NHTSAValidationError` | Input parameters are invalid or missing (raised before any request is made) |
| `NHTSAHTTPError` | NHTSA's API returns a non-2xx status after retries are exhausted |
| `NHTSARateLimitError` | NHTSA's API returns HTTP 429 after retries are exhausted (subclass of `NHTSAHTTPError`) |
| `NHTSATimeoutError` | A request times out on every retry attempt |
| `NHTSARequestError` | Another network-level failure occurs after retries |
| `NHTSAParseError` | The response body isn't valid JSON, or every record in a response fails schema validation |

Individual malformed records within an otherwise valid response are skipped and logged as a warning; a `NHTSAParseError` is only raised when an entire response fails to parse, since that typically indicates NHTSA has changed their schema.

## Configuration

Retry and timeout behavior can be tuned by constructing the lower-level HTTP client yourself:

```python
from nhtsa_recalls import RecallClient, NHTSAClient

http_client = NHTSAClient(timeout_seconds=30, max_retries=5)
with RecallClient(http_client=http_client) as client:
    df = client.get_by_vehicle(make="acura")
```

## Development

```bash
pip install -e ".[dev]"
pytest
mypy
```

## License

MIT
