Skip to content
FeedbackDashboard
Generate SDKs
Languages

Python

Generate production-ready Python SDKs from your OpenAPI specification

The Stainless Python SDK generator creates idiomatic, type-safe Python client libraries from your OpenAPI specification.

Example repositories:

To generate a Python SDK, add the python target to your Stainless configuration file:

targets:
python:
edition: python.2025-11-20
package_name: my_company_client
targets:
python:
# Specify the edition
edition: python.2025-11-20
# package_name is used for imports (e.g., "import my_company_client")
package_name: my_company_client
# project_name is the PyPI distribution name (e.g., "pip install my-company-client")
# If not specified, defaults to package_name
project_name: my-company-client
# Configure publishing
publish:
pypi: true

For a complete list of configuration options, see the Python target reference.

Editions allow Stainless to make improvements to SDKs that aren’t backwards-compatible. You can explicitly opt in to new editions when you’re ready. See the SDK and config editions reference for more information.

  • Changed default package manager from Rye to uv
  • To revert to Rye, set options.use_uv: false
  • Initial edition for Python (used by default if no edition is specified)

Package your Python SDK for distribution on PyPI, making it easy for users to install with pip install.

Trusted publishing uses OpenID Connect (OIDC) to authenticate with PyPI without requiring long-lived API tokens. This is the recommended approach for security.

(Option 1): Configure a new PyPI project
  1. Navigate to the publishing settings in your PyPI account, and scroll down to the Add a new pending publisher section.

  2. Enter the PyPI project name for your SDK. This should match the targets.python.package_name value in your Stainless config.

  3. Enter the Owner and the Repository name to match the GitHub repository’s location.

  4. Enter publish-pypi.yml as the Workflow name.

  5. [Recommended] If you utilize a specific GitHub Actions environment for releases, enter the Environment name. This will make it so only release workflows running in that environment can publish.

    The release environment is set in your Stainless config like so:

    codeflow:
    release_environment: <environment-name>
    # ...
  6. Click Add.

(Option 2): Configure an existing PyPI project
  1. Navigate to your project settings at pypi.org/manage/project/<package-name>/settings/publishing, and find the Add a new publisher section.

  2. Enter the Owner and the Repository name to match the GitHub repository’s location.

  3. Enter publish-pypi.yml as the Workflow name.

  4. [Recommended] If you utilize a specific GitHub Actions environment for releases, enter the Environment name. This will make it so only release workflows running in that environment can publish.

    The release environment is set in your Stainless config like so:

    codeflow:
    release_environment: <environment-name>
    # ...
  5. Click Add.

Update the Stainless config to specify OIDC authentication and save.

targets:
python:
package_name: <package-name>
publish:
pypi:
auth_method: oidc

Trusted publishing is only supported with the uv package manager. If you’re using rye you may get a No access token found error.

Ensure your config is on the python.2025-11-20 edition or higher:

targets:
python:
edition: python.2025-11-20

Why we don’t use Python’s Enum class for enums

Section titled “Why we don’t use Python’s Enum class for enums”

Stainless generates Python enums using Literal types instead of Python’s built-in Enum class. For example, instead of:

from enum import Enum
class Status(str, Enum):
PENDING = "pending"
COMPLETED = "completed"
FAILED = "failed"

We generate:

from typing_extensions import Literal
Status = Literal["pending", "completed", "failed"]

This is an intentional design decision based on several considerations:

Forward compatibility: Literal types ensure forward compatibility when new enum values are added to your API. If your server starts returning a new value like "cancelled" that wasn’t present when the SDK was generated, Literal types allow it to pass through gracefully. With Enum classes, you’d need to update the SDK and release a new version to handle new values.

Lightweight and developer-friendly: Literal types require no runtime overhead and less boilerplate. They provide excellent type checking and auto-completion in modern IDEs while keeping the generated code simple and readable.

Consistent philosophy: Across all our SDKs, we believe it’s better to let unexpected enum values pass through rather than breaking when new values are introduced. This approach prioritizes SDK stability and reduces the need for frequent breaking changes.

For more context on our design philosophy around forward compatibility, check out our blog post on Java enum compatibility — while Java doesn’t have literals like Python, it illustrates similar design considerations.