Metadata-Version: 2.4
Name: closecity
Version: 1.5.0
Summary: Python client for the Close API (api.close.city). Travel times to points of interest for every US census block.
Author-email: Henry Spatial Analysis <nat@henryspatialanalysis.com>, Nathaniel Henry <nat@henryspatialanalysis.com>
Maintainer-email: Henry Spatial Analysis <nat@henryspatialanalysis.com>
License-Expression: MIT
Project-URL: Homepage, https://close.city
Project-URL: Documentation, https://henryspatialanalysis.github.io/closecity-python/
Project-URL: Repository, https://github.com/henryspatialanalysis/closecity-python
Project-URL: Issues, https://github.com/henryspatialanalysis/closecity-python/issues
Project-URL: API, https://api.close.city
Keywords: close,travel-time,isochrone,census,accessibility,gis
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27
Requires-Dist: pandas>=1.5
Requires-Dist: geopandas>=0.14
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Provides-Extra: tiger
Requires-Dist: pygris; extra == "tiger"
Provides-Extra: maps
Requires-Dist: plotly>=5; extra == "maps"
Provides-Extra: docs
Requires-Dist: sphinx>=7; extra == "docs"
Requires-Dist: furo; extra == "docs"
Requires-Dist: sphinx-copybutton; extra == "docs"
Requires-Dist: myst-nb; extra == "docs"
Requires-Dist: jupytext; extra == "docs"
Requires-Dist: matplotlib; extra == "docs"
Requires-Dist: pygris; extra == "docs"
Requires-Dist: plotly>=5; extra == "docs"
Dynamic: license-file

# closecity

This is the Python software development kit for the Close.City API. It returns
travel times from every US census block to nearby places, on foot, by bike, and by
public transit. The data behind [close.city](https://close.city) is served over the
[Close API](https://api.close.city).

**Documentation:** https://henryspatialanalysis.github.io/closecity-python/

## Install

Will soon be on PyPI; install from GitHub until then:

```bash
pip install git+https://github.com/henryspatialanalysis/closecity-python.git
# add the census-block boundary downloader:
pip install "closecity[tiger] @ git+https://github.com/henryspatialanalysis/closecity-python.git"
```

This pulls in `httpx`, `pandas`, and `geopandas`, so results come back as data
frames out of the box: a GeoDataFrame where geometry applies, a plain DataFrame
otherwise.

## A first call

You make requests through a client. Routes with geometry come back as
GeoDataFrames, so you can map them right away.

```python
from closecity import Client, close_map

# The key (ck_live_) comes from https://account.close.city (5,000 free tokens
# on signup, no card). You can also set the CLOSECITY_KEY environment variable
# and call Client() with no argument.
close = Client("ck_live_your_key")   # use your own key here

# Supermarkets within a 1.5 km walk of a point (type 30 is grocery stores):
supermarkets = close.pois_search(lat = 41.823, lon = -71.412, radius_m = 1500, type = 30)
close_map(supermarkets, color = "#e8590c")   # interactive map, bright hoverable points
```

Catalog and lookup routes are free, need no key, and come back as data frames:

```python
close = Client()
close.modes()                  # walk, bike, transit
close.places("Providence")     # a city name to its GEOID and centre
```

## Key terms

A few terms come up throughout the API:

- **Census block.** The smallest area the Census Bureau publishes. Each one has a
  15-digit id called a **GEOID**.
- **Destination type.** A category of place, such as grocery stores or libraries.
  Each type has a numeric id. Look them up with `close.destination_types()`.
- **Mode.** How someone travels: walk, bike, or transit.
- **Isochrone** or **catchment**: the area you can reach starting from a point
  within a time limit, by a selected travel mode.

## Choose an output

Set `output` on the client, or per call:

- `output = "spatial"` (the default) returns a GeoDataFrame for inherently spatial
  data and a DataFrame otherwise. Block routes join census-block boundaries with
  `pygris` (the `tiger` extra), downloaded once and cached.
- `output = "tabular"` returns a plain DataFrame for every route and never
  downloads boundaries. Reach for it when you only want the numbers.
- `output = "raw"` returns the underlying `Reply` / `Paginator`, with the parsed
  body on `.data` and the token counts alongside.

```python
close = Client("ck_live_your_key", output = "raw")   # use your own key here
for poi in close.pois_search(lat = 41.823, lon = -71.412, radius_m = 1500):
    print(poi["name"])
```

## Handling errors

Problem responses become typed exceptions. Catch a specific one, or the
`CloseAPIError` base.

```python
from closecity import TokensExhaustedError, CloseAPIError

try:
    close.block_summary("000000000000000")
except TokensExhaustedError:
    ...
except CloseAPIError as err:
    print(err.status, err.slug)
```

The client does not retry automatically. On a `RateLimitedError` or
`ServiceUnavailableError`, wait `err.retry_after` seconds (from the
`Retry-After` header) and retry the request yourself.

## Reference

- Documentation: https://henryspatialanalysis.github.io/closecity-python/
- Interactive API: https://api.close.city/docs
- Machine-readable contract: https://api.close.city/openapi.json

## Development

```bash
pip install -e '.[dev]'
pytest        # unit tests, no network (httpx MockTransport)
ruff check src tests
```
