Autogenerated and fully typed OpenAPI Python clients with a developer-friendly, ergonomic interface.
Project description
openapi-python
openapi-python generates strongly typed Python API clients from OpenAPI specs, with a developer-friendly and ergonomic string-literal-based interface strongly inspired by openapi-typescript.
Installation
For generated clients that use the built-in httpx transport:
uv add openapi-python[httpx]
For protocol-only generated clients where you provide the transport:
uv add openapi-python
CLI
Generate a client from an OpenAPI spec in openapi.json:
uv run openapi-python generate --spec ./openapi.json --out ./generated --package my_client
Programmatic API
from pathlib import Path
from openapi_python import GenerationRequest, generate_client
result = generate_client(
GenerationRequest(
spec_source="./openapi.json",
output_dir=Path("./generated"),
package_name="my_client",
overwrite=True,
)
)
Using generated clients
Generated clients expose route-specific callables with typed params, query, headers, body, and return values.
With the built-in httpx transport:
from generated.my_client import Client
client = Client(base_url="https://api.example.com")
book = client.get("/books/{book_id}")(params={"book_id": 1})
For async APIs:
from generated.my_client import AsyncClient
async_client = AsyncClient(base_url="https://api.example.com")
book = await async_client.get("/books/{book_id}")(params={"book_id": 1})
For protocol-only clients, provide your own transport:
from generated.my_client import Client
client = Client(base_url="https://api.example.com", transport=my_transport)
book = client.get("/books/{book_id}")(params={"book_id": 1})
Extensibility
GeneratorExtensions exposes two safe hooks:
normalize_hooks: transform the normalized model before rendering.render_context_hooks: transform rendered file content map before writing.
Transport Decoupling
Generated clients expose a transport protocol. You can plug in your own transport while keeping route-level typing guarantees.
Use --transport-mode protocol-only to generate clients that require a supplied transport and do not emit the built-in httpx transport classes. The default --transport-mode default includes DefaultTransport and DefaultAsyncTransport, which require the httpx extra when instantiated.
Built-in httpx transport
Install the httpx extra and generate with the default transport mode:
uv add "openapi-python[httpx]"
uv run openapi-python generate --spec ./openapi.json --out ./generated --package my_client
You can supply preconfigured httpx clients:
import httpx
from generated.my_client import AsyncClient, Client, DefaultAsyncTransport, DefaultTransport
sync_http = httpx.Client(headers={"authorization": "Bearer token"})
async_http = httpx.AsyncClient(headers={"authorization": "Bearer token"})
client = Client(
base_url="https://api.example.com",
transport=DefaultTransport(client=sync_http),
)
async_client = AsyncClient(
base_url="https://api.example.com",
transport=DefaultAsyncTransport(client=async_http),
)
Custom transport
Install openapi-python without extras and generate protocol-only code:
uv add openapi-python requests
uv run openapi-python generate \
--spec ./openapi.json \
--out ./generated \
--package my_client \
--transport-mode protocol-only
Then provide an object that satisfies the generated Transport protocol:
from collections.abc import Mapping
import requests
from generated.my_client import Client
class RequestsTransport:
def request(
self,
*,
method: str,
route: str,
base_url: str,
params: Mapping[str, object] | None,
query: Mapping[str, object] | None,
headers: Mapping[str, object] | None,
body: object | None,
) -> object:
response = requests.request(
method=method.upper(),
url=f"{base_url.rstrip('/')}{route.format(**(params or {}))}",
params={key: str(value) for key, value in (query or {}).items()} or None,
headers={key: str(value) for key, value in (headers or {}).items()} or None,
json=body,
)
response.raise_for_status()
if response.content:
return response.json()
return None
client = Client(
base_url="https://api.example.com",
transport=RequestsTransport(),
)
book = client.get("/books/{book_id}")(params={"book_id": 1})
Releases
Releases are published from the protected releases branch. The package version is set manually in pyproject.toml, and pushing a release commit to releases triggers the GitHub Actions release workflow. The workflow creates the matching vX.Y.Z tag after checks pass.
Before the first release, configure PyPI Trusted Publishing for this repository:
- PyPI project:
openapi-python - GitHub workflow:
release.yml - GitHub environment:
pypi
The GitHub pypi environment should be limited to deployments from the releases branch.
Release steps:
# 1. Update project.version in pyproject.toml, then commit that change.
uv run python scripts/release.py --version 0.1.0
# 2. If checks pass, push the current commit to the releases branch.
uv run python scripts/release.py --version 0.1.0 --push-release-branch
The release workflow verifies that the version tag does not already exist, runs checks, builds the distributions, validates them with twine, creates the release tag, publishes to PyPI, and creates a GitHub Release with generated notes.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openapi_python-0.0.3.tar.gz.
File metadata
- Download URL: openapi_python-0.0.3.tar.gz
- Upload date:
- Size: 18.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4932aa5752a9bc9a329aaa07e81bcff0bf01ea2441f630d5d4d5860725deaef6
|
|
| MD5 |
98d31ae72a15e25d8714023e77dc3e74
|
|
| BLAKE2b-256 |
b0490f83d513303b2c89d591e4c5bb11286f31da6e06d64132923ea8006e34e8
|
Provenance
The following attestation bundles were made for openapi_python-0.0.3.tar.gz:
Publisher:
release.yml on Minibrams/openapi-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openapi_python-0.0.3.tar.gz -
Subject digest:
4932aa5752a9bc9a329aaa07e81bcff0bf01ea2441f630d5d4d5860725deaef6 - Sigstore transparency entry: 1370162442
- Sigstore integration time:
-
Permalink:
Minibrams/openapi-python@f6c85e46726e2ea59069d1e9c40b5e61f1961e99 -
Branch / Tag:
refs/heads/releases - Owner: https://github.com/Minibrams
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6c85e46726e2ea59069d1e9c40b5e61f1961e99 -
Trigger Event:
push
-
Statement type:
File details
Details for the file openapi_python-0.0.3-py3-none-any.whl.
File metadata
- Download URL: openapi_python-0.0.3-py3-none-any.whl
- Upload date:
- Size: 26.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
641078b5c5f671e43d2cd782dd8c1370a9a8fede8b0ab5c8b4ab9b325f54a5a8
|
|
| MD5 |
b9bf6062a22001de4f58f8b1c336b55c
|
|
| BLAKE2b-256 |
7de856000456db3d14a2f38a11ffb5ad2d5424f8757138bedf6da23cdb9e95f9
|
Provenance
The following attestation bundles were made for openapi_python-0.0.3-py3-none-any.whl:
Publisher:
release.yml on Minibrams/openapi-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openapi_python-0.0.3-py3-none-any.whl -
Subject digest:
641078b5c5f671e43d2cd782dd8c1370a9a8fede8b0ab5c8b4ab9b325f54a5a8 - Sigstore transparency entry: 1370162537
- Sigstore integration time:
-
Permalink:
Minibrams/openapi-python@f6c85e46726e2ea59069d1e9c40b5e61f1961e99 -
Branch / Tag:
refs/heads/releases - Owner: https://github.com/Minibrams
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f6c85e46726e2ea59069d1e9c40b5e61f1961e99 -
Trigger Event:
push
-
Statement type: