Skip to content

feat!: Generate the Python SDK via the OpenAPI spec#604

Open
gjtorikian wants to merge 27 commits intonext-majorfrom
oagen
Open

feat!: Generate the Python SDK via the OpenAPI spec#604
gjtorikian wants to merge 27 commits intonext-majorfrom
oagen

Conversation

@gjtorikian
Copy link
Copy Markdown
Contributor

This branch moves the Python SDK from the old handwritten surface to the OpenAPI-generated client surface, with a small set of targeted aliases kept where they still help. The result is a much larger API, more consistent resource naming, better typed request and error handling, and a cleaner package layout for the next major release.

Removed

Handwritten compatibility internals

  • Removed the old client internals and compatibility plumbing:
    • src/workos/_base_client.py
    • src/workos/_client_configuration.py
    • src/workos/client.py
    • src/workos/async_client.py
  • Removed the legacy exception module at src/workos/exceptions.py.
  • Removed the legacy src/workos/types/ tree and its broad re-export surface.

Flat handwritten resource modules

  • Removed the old single-file resource implementations in favor of generated resource packages.
  • That includes legacy modules such as:
    • src/workos/api_keys.py
    • src/workos/audit_logs.py
    • src/workos/authorization.py
    • src/workos/connect.py
    • src/workos/directory_sync.py
    • src/workos/organizations.py
    • src/workos/portal.py
    • src/workos/user_management.py
  • Removed a large amount of handwritten test utility scaffolding that only existed to support the old surface.

Old tooling and model assumptions

  • Removed pydantic from the runtime dependencies; @dataclass is now used instead.
  • Removed mypy as the primary type checker in favor of pyright.
  • Removed the old WorkOSListResource-style pagination surface.

Added

Generated sync and async clients

  • Added generated WorkOSClient and AsyncWorkOSClient as the main SDK entrypoints.
  • Kept top-level WorkOS and AsyncWorkOS aliases for ergonomics.
  • Added shared generated request handling with:
    • httpx sync/async clients
    • retry/backoff support
    • automatic POST idempotency keys
    • per-request overrides through RequestOptions

Generated resource packages and models

  • Added generated resource packages across the SDK, including:
    • admin_portal
    • applications
    • application_client_secrets
    • connections
    • directories
    • directory_groups
    • directory_users
    • feature_flags
    • multi_factor_auth
    • permissions
    • radar
    • workos_connect
  • Added generated dataclass-style models with from_dict() / to_dict() behavior.
  • Added generated pagination types:
    • SyncPage
    • AsyncPage

Better runtime error handling

  • Added a normalized exception hierarchy in src/workos/_errors.py.
  • Exceptions now consistently expose fields like status_code, message, request_id, raw_body, request_url, and request_method.
  • Added explicit timeout and connection exceptions:
    • WorkOSTimeoutException
    • WorkOSConnectionException

Coverage and maintenance improvements

  • Added broad generated test coverage, including model round-trip tests and generated client tests.
  • Added a dedicated lint workflow and pyrightconfig.json.
  • Added pytest-httpx for HTTP client testing.

Changed

Public API shape

  • The SDK now centers on generated resource namespaces instead of the old handwritten helper modules.
  • Several legacy top-level aliases are gone or split up:
    • client.connect becomes client.applications and client.application_client_secrets
    • client.directory_sync becomes client.directories, client.directory_groups, and client.directory_users
    • client.portal becomes client.admin_portal
  • Some compatibility aliases were intentionally kept:
    • WorkOS / AsyncWorkOS
    • client.mfa as an alias for client.multi_factor_auth
    • client.user_management.load_sealed_session(...)
    • selected resource-level compatibility methods in areas like Admin Portal, Audit Logs, and Authorization

Client configuration expectations

  • Minimum supported Python is now 3.10+.
  • Client construction now accepts either api_key or client_id, and only raises if neither is configured.
  • Flows that rely on a client ID fallback still require client_id at call time, via constructor configuration, or through WORKOS_CLIENT_ID.
  • Retry behavior is now built into the generated client and can be configured globally or per request.

Model behavior

  • SDK models are no longer Pydantic models.
  • Code that relied on model_validate(), model_dump(), or other Pydantic behaviors now needs to move to the generated dataclass-style API.
  • Direct model imports should come from generated workos.<resource>.models packages rather than workos.types.*.

Development workflow

  • Type checking moved from mypy to pyright --strict.
  • Dependency baselines were refreshed, including the Python floor and package constraints.
  • CI and local dev scripts now reflect the generated-client world instead of the old handwritten one.

Migration Notes

Biggest user-facing updates

  • Import clients from workos, not workos.client / workos.async_client.
  • Update code that used old helper namespaces like connect, portal, and directory_sync.
  • Update any code treating SDK models as Pydantic models.
  • Review flows that depend on client_id defaults and either pass it explicitly or configure it on the client / environment.
  • If you depend on 5.x-style “fail immediately” request behavior, set max_retries=0.

What should feel familiar

  • Top-level client construction is still straightforward.
  • Sync and async clients still exist.
  • Sealed session loading still has a first-class helper.
  • A few high-value aliases remain in place to keep the upgrade from being harsher than it needs to be.

gjtorikian and others added 27 commits March 26, 2026 23:45
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace mypy with pyright as the primary type checker. pyright is
faster, catches more real bugs (better type narrowing, generic
inference, union handling), and is the industry standard for production
Python SDKs (used by OpenAI, Anthropic, Stripe).

- Replace mypy with pyright in noxfile.py (typecheck + ci sessions)
- Swap mypy for pyright in type_check dependency group
- Remove [tool.mypy] config section
- Add [tool.pyright] with typeCheckingMode = "strict"
- Update uv.lock

The generated SDK passes pyright strict with 0 errors across 374 files.

This also addresses #600 (SsoProviderType enum removal) — the emitter
generates all spec enums as str/Enum classes, restoring attribute
access (e.g., EnumName.VALUE) that was lost when v5 switched to
Literal type aliases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add pyrightconfig.json to configure pyright for this codebase
- Fix test type errors with proper annotations and constructors
- Fix dead assertions in test_audit_logs.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rning

Future pytest-asyncio versions will default async fixture loop scope to
"function". Set it explicitly to avoid surprises on upgrade.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete the entire legacy stack that the generated code replaces:

- All 10 _compat.py bridge files
- All handwritten service modules (sso.py, connect.py, etc.)
- Old client.py, async_client.py, _base_client.py, _client_configuration.py
- Entire types/ directory (~170 files of Pydantic models)
- typing/ directory (legacy type helpers)
- utils/ directory (legacy HTTP client, request helpers)
- exceptions.py (replaced by _errors.py)
- All legacy test files and fixtures

The generated _resource.py + _client.py + models/ are now the sole
implementation. Update __init__.py to export from the generated
_client.py. Add new conftest.py with workos/async_workos fixtures
for the generated test suite.

436 tests pass, 0 failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add all auto-generated resource modules, models, types, and tests
- Add verify_event/verify_header back to Webhooks as @oagen-ignore methods
- Add list_connections/get_connection/delete_connection to SSO as @oagen-ignore methods
- Rename organizations update_organization→update, delete_organization→delete
- Fix docstring exception names (*Error→*Exception) across all resource files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regenerated from updated emitter with:
- Audit log exports: exports/export -> create_export/get_export
- Authorization role permissions: unwieldy names replaced with
  set_organization_role_permissions, add_organization_role_permission, etc.
- Default request timeout restored to 30s (was 25s)
- Event model hand-maintained via oagen-ignore with id, event, data,
  created_at fields (emitter produces empty placeholder for oneOf unions)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regenerated from updated emitter that no longer emits unnecessary
`pass` in models with zero fields, fixing ruff format CI failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The generated Event stub is now replaced by the @oagen-ignore block
version, eliminating the F811 duplicate class definition lint error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regenerated from updated oagen core (top-level @oagen-ignore replacement)
and emitters (skip fixtures/tests for empty discriminated union models).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restores `from workos.exceptions import ...` and `from workos.types.<service> import ...`
import paths. Updates V6 migration guide to remove these as breaking changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gjtorikian gjtorikian requested review from a team as code owners April 1, 2026 17:09
@gjtorikian gjtorikian removed the request for review from a team April 1, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants