Async vs Sync¶
harvest-forecast-py provides two interchangeable clients: an async client for asyncio-based
applications and a sync client for traditional synchronous code. Both expose the same methods with
identical signatures — the only difference is await and the import path.
Two clients, one codebase¶
| Client | Class | Import | Use case |
|---|---|---|---|
| Async | AsyncForecastClient (aliased as ForecastClient) |
from harvest_forecast import ForecastClient |
asyncio apps, FastAPI, aiohttp |
| Sync | SyncForecastClient |
from harvest_forecast import SyncForecastClient |
Scripts, CLIs, Jupyter, Django |
The async client is the canonical implementation. The sync client is generated from it using the
unasync library, which mechanically transforms async def
into def, await into nothing, and AsyncClient into Client.
When to use which¶
- Your application already runs on
asyncio(FastAPI, aiohttp, Starlette) - You need concurrent requests to multiple endpoints
- You're building a long-running service that makes many API calls
- You're writing a script or one-off tool
- You're in a synchronous framework (Django, Flask without async views)
- You're in a REPL or Jupyter notebook
- You want the simplest possible code
Import paths¶
The async client is exported as ForecastClient for convenience. The sync client is exported as
SyncForecastClient.
# Async — the canonical implementation
from harvest_forecast import ForecastClient # this is AsyncForecastClient
# Sync — generated from the async client
from harvest_forecast import SyncForecastClient
If you need the async client by its real name, import from the internal module:
Context manager usage¶
Both clients support context manager protocol to ensure the underlying HTTP connection pool is closed. Always use the context manager to avoid resource leaks.
Manual close¶
If you don't use the context manager, call the close method explicitly:
Method names differ for close
The async client uses aclose() and the sync client uses close(). This is the one API difference beyond await.
The unasync generation approach¶
The sync client is not maintained by hand. The source of truth lives in src/harvest_forecast/_async/
and is transformed into src/harvest_forecast/_sync/ by the build script:
The transformation rules (defined in scripts/unasync.py) are:
| Async token | Sync token |
|---|---|
AsyncForecastClient |
SyncForecastClient |
AsyncClient |
Client |
AsyncRetrying |
Retrying |
aclose |
close |
_async |
_sync |
This guarantees the two clients stay in sync — any method added to the async client automatically
appears in the sync client after running make unasync.
Don't edit _sync/ directly
The _sync/ directory is excluded from linting (ruff excludes it) and is regenerated from
_async/. Always edit the async source and regenerate.
Next steps¶
- Quick Start — Side-by-side async and sync examples
- API Reference: Client — Full method documentation