Skip to main content

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 route-literal dispatch and transport decoupling.

Installation

For protocol-only generated clients where you provide the transport:

uv add openapi-python

For generated clients that use the built-in httpx transport:

uv add "openapi-python[httpx]"

CLI

uv run openapi-python generate --spec ./openapi.json --out ./generated --package my_client

You can also pass the OpenAPI document directly as JSON:

uv run openapi-python generate --spec-json "$OPENAPI_JSON" --out ./generated --package my_client

For URL specs with self-signed certificates, disable verification explicitly:

uv run openapi-python generate --spec https://example.local/openapi.json --out ./generated --no-ssl

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,
    )
)

To generate from an in-memory OpenAPI document, pass a JSON string instead of spec_source:

import json
from pathlib import Path

from openapi_python import GenerationRequest, generate_client

result = generate_client(
    GenerationRequest(
        output_dir=Path("./generated"),
        spec_json=json.dumps(app.openapi()),
        package_name="my_client",
        overwrite=True,
    )
)

Extensibility

GeneratorExtensions exposes two safe hooks:

  • normalize_hooks: transform the normalized model before rendering.
  • render_context_hooks: transform rendered file content map before writing.

Invalid extension outputs fail fast with explicit diagnostics.

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.

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-runtime 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

The generated Client can create its own default 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})

You can also 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})

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

openapi_python-0.0.1.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openapi_python-0.0.1-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

File details

Details for the file openapi_python-0.0.1.tar.gz.

File metadata

  • Download URL: openapi_python-0.0.1.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for openapi_python-0.0.1.tar.gz
Algorithm Hash digest
SHA256 d7b5cba89a143ab9599e18d3cca73b28a5a1395ab35b8ed4c99e0b30a1a60010
MD5 9941b630a5d94388487ad856f7a1ea32
BLAKE2b-256 b065822688a054cfb17af31f573145cd2fd775fde9ba487f2060cb23a93cc966

See more details on using hashes here.

Provenance

The following attestation bundles were made for openapi_python-0.0.1.tar.gz:

Publisher: release.yml on Minibrams/openapi-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openapi_python-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: openapi_python-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 20.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for openapi_python-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fe352caf5083592758ec48c9b720722b23f323f0b1d8324ac0459bcc6161eaa5
MD5 0eb4be0db6e9b37eeec6b4e56393b96a
BLAKE2b-256 e58771d388fffac64c0c746b2edea8aa67f42ed03319d723cdddff4d375c3f18

See more details on using hashes here.

Provenance

The following attestation bundles were made for openapi_python-0.0.1-py3-none-any.whl:

Publisher: release.yml on Minibrams/openapi-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page