Skip to content

Commit 9f67477

Browse files
gjtorikianclaude
andauthored
feat!: Generate the Python SDK via the OpenAPI spec (#604)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ec9a3fd commit 9f67477

File tree

1,882 files changed

+81536
-26051
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,882 files changed

+81536
-26051
lines changed

CLAUDE.md

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44

5+
## Code Generation
6+
7+
Most of the SDK is **auto-generated** by `oagen` (an internal OpenAPI code generator). Generated files begin with `# This file is auto-generated by oagen. Do not edit.` Hand-maintained code is fenced with `@oagen-ignore-start` / `@oagen-ignore-end` markers or marked with `# @oagen-ignore-file` (e.g., `session.py`, `passwordless.py`, `vault.py`, `public_client.py`, `pkce.py`, `actions.py`).
8+
59
## Development Commands
610

711
### Installation and Setup
@@ -16,7 +20,7 @@ uv sync --locked --dev # Install package in development mode with dev dependenci
1620
uv run ruff format . # Format code
1721
uv run ruff format --check . # Check formatting without making changes
1822
uv run ruff check . # Lint code
19-
uv run mypy # Type checking
23+
uv run pyright # Type checking
2024
```
2125

2226
### Testing
@@ -69,50 +73,58 @@ bash scripts/build_and_upload_dist.sh # Build and upload to PyPI
6973

7074
The SDK provides both synchronous and asynchronous clients:
7175

72-
- `WorkOSClient` (sync) and `AsyncWorkOSClient` (async) are the main entry points
73-
- Both inherit from `BaseClient` which handles configuration and module initialization
74-
- Each feature area (SSO, Directory Sync, etc.) has dedicated module classes
75-
- HTTP clients (`SyncHTTPClient`/`AsyncHTTPClient`) handle the actual API communication
76+
- `WorkOSClient` (sync) and `AsyncWorkOSClient` (async) are the main entry points (exported from `workos/__init__.py`)
77+
- Both inherit from `_BaseWorkOSClient` (in `workos/_client.py`) which handles configuration, HTTP transport, retry logic, and error mapping
78+
- Each feature area (SSO, Organizations, etc.) is exposed as a `@functools.cached_property` on the client for lazy loading
79+
- HTTP transport uses `httpx` directly; there is no separate HTTP client abstraction layer
7680

7781
### Module Structure
7882

79-
Each WorkOS feature has its own module following this pattern:
83+
Each feature module follows this layout:
84+
85+
```
86+
src/workos/{module_name}/
87+
__init__.py # Re-exports from _resource and models
88+
_resource.py # Sync and Async resource classes (e.g., SSO + AsyncSSO)
89+
models/
90+
__init__.py # Re-exports all model classes
91+
{model}.py # Individual dataclass model files
92+
```
8093

81-
- **Module class** (e.g., `SSO`) - main API interface
82-
- **Types directory** (e.g., `workos/types/sso/`) - Pydantic models for API objects
83-
- **Tests** (e.g., `tests/test_sso.py`) - comprehensive test coverage
94+
Resource classes take a `WorkOSClient` or `AsyncWorkOSClient` client reference and call `self._client.request()` or `self._client.request_page()` for paginated endpoints.
8495

8596
### Type System
8697

87-
- All models inherit from `WorkOSModel` (extends Pydantic `BaseModel`)
88-
- Strict typing with mypy enforcement (`strict = True` in mypy.ini)
89-
- Support for both sync and async operations via `SyncOrAsync` typing
98+
- All models use `@dataclass(slots=True)`**not** Pydantic
99+
- Each model implements `from_dict(cls, data) -> Self` for deserialization and `to_dict() -> Dict` for serialization
100+
- The `Deserializable` protocol in `workos/_types.py` defines the `from_dict` contract
101+
- `RequestOptions` (a `TypedDict`) allows per-call overrides for headers, timeout, retries, etc.
102+
- Type checking uses **pyright** (configured in `pyrightconfig.json`)
90103

91-
### Testing Framework
104+
### Pagination
92105

93-
- Uses pytest with custom fixtures for mocking HTTP clients
94-
- `@pytest.mark.sync_and_async()` decorator runs tests for both sync/async variants
95-
- Comprehensive fixtures in `conftest.py` for HTTP mocking and pagination testing
96-
- Test utilities in `tests/utils/` for common patterns
106+
- `SyncPage[T]` and `AsyncPage[T]` dataclasses in `workos/_pagination.py` represent paginated results
107+
- Cursor-based: `before`/`after` properties, `has_more()` check
108+
- `auto_paging_iter()` transparently fetches subsequent pages
97109

98-
### HTTP Client Abstraction
110+
### Error Handling
99111

100-
- Base HTTP client (`_BaseHTTPClient`) with sync/async implementations
101-
- Request helper utilities for consistent API interaction patterns
102-
- Built-in pagination support with `WorkOSListResource` type
103-
- Automatic retry and error handling
112+
All exceptions live in `workos/_errors.py` and inherit from `WorkOSError`:
104113

105-
### Key Patterns
114+
- `BadRequestError` (400), `AuthenticationError` (401), `AuthorizationError` (403), `NotFoundError` (404), `ConflictError` (409), `UnprocessableEntityError` (422), `RateLimitExceededError` (429), `ServerError` (5xx)
115+
- `ConfigurationError`, `WorkOSConnectionError`, `WorkOSTimeoutError` for non-HTTP errors
116+
- `STATUS_CODE_TO_ERROR` dict maps status codes to exception classes
117+
118+
### Testing Framework
106119

107-
- **Dual client support**: Every module supports both sync and async operations
108-
- **Type safety**: Extensive use of Pydantic models and strict mypy checking
109-
- **Pagination**: Consistent cursor-based pagination across list endpoints
110-
- **Error handling**: Custom exception classes in `workos/exceptions.py`
111-
- **Configuration**: Environment variable support (`WORKOS_API_KEY`, `WORKOS_CLIENT_ID`)
120+
- Uses **pytest** with **pytest-httpx** for HTTP mocking (provides the `httpx_mock` fixture)
121+
- Separate test classes for sync (`TestSSO`) and async (`TestAsyncSSO`) variants
122+
- Async tests use `@pytest.mark.asyncio`
123+
- JSON fixtures in `tests/fixtures/`, loaded via `load_fixture()` from `tests/generated_helpers.py`
124+
- Client fixtures `workos` and `async_workos` defined in `tests/conftest.py`
112125

113-
When adding new features:
126+
### Configuration
114127

115-
1. Create module class with both sync/async HTTP client support
116-
2. Add Pydantic models in appropriate `types/` subdirectory
117-
3. Implement comprehensive tests using the sync_and_async marker
118-
4. Follow existing patterns for pagination, error handling, and type annotations
128+
- Environment variable support: `WORKOS_API_KEY`, `WORKOS_CLIENT_ID`, `WORKOS_BASE_URL`, `WORKOS_REQUEST_TIMEOUT`
129+
- Retry logic: exponential backoff with jitter, retries on 429/5xx, respects `Retry-After` headers
130+
- Default timeout: 60 seconds

README.md

Lines changed: 126 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,68 +3,166 @@
33
![PyPI](https://img.shields.io/pypi/v/workos)
44
[![Build Status](https://workos.semaphoreci.com/badges/workos-python/branches/main.svg?style=shields&key=9e4cb5bb-86a4-4938-9ec2-fc9f9fc512be)](https://workos.semaphoreci.com/projects/workos-python)
55

6-
The WorkOS library for Python provides convenient access to the WorkOS API from applications written in Python, [hosted on PyPi](https://pypi.org/project/workos/)
6+
The WorkOS library for Python provides convenient access to the WorkOS API from applications written in Python, [hosted on PyPI](https://pypi.org/project/workos/).
77

88
## Documentation
99

1010
See the [API Reference](https://workos.com/docs/reference/client-libraries) for Python usage examples.
1111

1212
## Installation
1313

14-
To install from PyPi, run the following:
15-
16-
```
14+
```bash
1715
pip install workos
1816
```
1917

20-
To install from source, clone the repo and run the following:
18+
## Quick Start
2119

22-
```
23-
python -m pip install .
20+
```python
21+
from workos import WorkOSClient
22+
23+
client = WorkOSClient(api_key="sk_1234", client_id="client_1234")
24+
25+
# List organizations
26+
page = client.organizations.list_organizations()
27+
for org in page.auto_paging_iter():
28+
print(org.name)
29+
30+
# Create an organization
31+
org = client.organizations.create_organizations(name="Acme Corp")
32+
print(org.id)
2433
```
2534

26-
## Configuration
35+
### Async Client
2736

28-
The package will need to be configured with your [api key and client ID](https://dashboard.workos.com/api-keys).
37+
Every method has an identical async counterpart:
2938

3039
```python
31-
from workos import WorkOSClient
40+
from workos import AsyncWorkOSClient
3241

33-
workos_client = WorkOSClient(
34-
api_key="sk_1234", client_id="client_1234"
35-
)
42+
async_client = AsyncWorkOSClient(api_key="sk_1234", client_id="client_1234")
43+
44+
page = await async_client.organizations.list_organizations()
45+
async for org in page.auto_paging_iter():
46+
print(org.name)
3647
```
3748

38-
The SDK also provides asyncio support for some SDK methods, via the async client:
49+
### Environment Variables
50+
51+
The client reads credentials from the environment when not passed explicitly:
52+
53+
| Variable | Description |
54+
|----------|-------------|
55+
| `WORKOS_API_KEY` | WorkOS API key |
56+
| `WORKOS_CLIENT_ID` | WorkOS client ID |
57+
| `WORKOS_BASE_URL` | Override the API base URL (defaults to `https://api.workos.com/`) |
58+
| `WORKOS_REQUEST_TIMEOUT` | HTTP timeout in seconds (defaults to `60`) |
59+
60+
## Available Resources
61+
62+
The client exposes the full WorkOS API through typed namespace properties:
63+
64+
| Property | Description |
65+
|----------|-------------|
66+
| `client.sso` | Single Sign-On connections and authorization |
67+
| `client.organizations` | Organization management |
68+
| `client.user_management` | Users, identities, auth methods, invitations |
69+
| `client.directory_sync` | Directory connections and directory users/groups |
70+
| `client.admin_portal` | Admin Portal link generation |
71+
| `client.audit_logs` | Audit log events, exports, and schemas |
72+
| `client.authorization` | Fine-Grained Authorization (FGA) resources, roles, permissions, and checks |
73+
| `client.webhooks` | Webhook event verification |
74+
| `client.feature_flags` | Feature flag evaluation |
75+
| `client.api_keys` | Organization API key management |
76+
| `client.connect` | OAuth application management |
77+
| `client.widgets` | Widget session tokens |
78+
| `client.multi_factor_auth` | MFA enrollment and verification (also available as `client.mfa`) |
79+
| `client.pipes` | Data Integrations |
80+
| `client.radar` | Radar risk scoring |
81+
| `client.passwordless` | Passwordless authentication sessions |
82+
| `client.vault` | Encrypted data vault |
83+
84+
## Pagination
85+
86+
Paginated endpoints return `SyncPage[T]` (or `AsyncPage[T]`) with built-in auto-pagination:
3987

4088
```python
41-
from workos import AsyncWorkOSClient
89+
# Iterate through all pages automatically
90+
for user in client.user_management.list_users().auto_paging_iter():
91+
print(user.email)
92+
93+
# Or work with a single page
94+
page = client.user_management.list_users(limit=10)
95+
print(page.data) # List of items on this page
96+
print(page.has_more()) # Whether more pages exist
97+
print(page.after) # Cursor for the next page
98+
```
99+
100+
## Error Handling
101+
102+
All API errors map to typed exception classes with rich context:
103+
104+
```python
105+
from workos._errors import NotFoundError, RateLimitExceededError
106+
107+
try:
108+
client.organizations.get_organization("org_nonexistent")
109+
except NotFoundError as e:
110+
print(f"Not found: {e.message}")
111+
print(f"Request ID: {e.request_id}")
112+
except RateLimitExceededError as e:
113+
print(f"Retry after: {e.retry_after} seconds")
114+
```
115+
116+
| Exception | Status Code |
117+
|-----------|-------------|
118+
| `BadRequestError` | 400 |
119+
| `AuthenticationError` | 401 |
120+
| `AuthorizationError` | 403 |
121+
| `NotFoundError` | 404 |
122+
| `ConflictError` | 409 |
123+
| `UnprocessableEntityError` | 422 |
124+
| `RateLimitExceededError` | 429 |
125+
| `ServerError` | 5xx |
42126

43-
async_workos_client = AsyncWorkOSClient(
44-
api_key="sk_1234", client_id="client_1234"
127+
## Per-Request Options
128+
129+
Every method accepts `request_options` for per-call overrides:
130+
131+
```python
132+
result = client.organizations.list_organizations(
133+
request_options={
134+
"timeout": 10,
135+
"max_retries": 5,
136+
"extra_headers": {"X-Custom": "value"},
137+
"idempotency_key": "my-key",
138+
"base_url": "https://staging.workos.com/",
139+
}
45140
)
46141
```
47142

143+
## Type Safety
144+
145+
This SDK ships with full type annotations (`py.typed` / PEP 561) and works with mypy, pyright, and IDE autocompletion out of the box. All models are `@dataclass(slots=True)` classes with `from_dict()` / `to_dict()` for serialization.
146+
48147
## SDK Versioning
49148

50-
For our SDKs WorkOS follows a Semantic Versioning ([SemVer](https://semver.org/)) process where all releases will have a version X.Y.Z (like 1.0.0) pattern wherein Z would be a bug fix (e.g., 1.0.1), Y would be a minor release (1.1.0) and X would be a major release (2.0.0). We permit any breaking changes to only be released in major versions and strongly recommend reading changelogs before making any major version upgrades.
149+
WorkOS follows [Semantic Versioning](https://semver.org/). Breaking changes are only released in major versions. We strongly recommend reading changelogs before making major version upgrades.
51150

52151
## Beta Releases
53152

54-
WorkOS has features in Beta that can be accessed via Beta releases. We would love for you to try these
55-
and share feedback with us before these features reach general availability (GA). To install a Beta version,
56-
please follow the [installation steps](#installation) above using the Beta release version.
57-
58-
> Note: there can be breaking changes between Beta versions. Therefore, we recommend pinning the package version to a
59-
> specific version. This way you can install the same version each time without breaking changes unless you are
60-
> intentionally looking for the latest Beta version.
153+
WorkOS has features in Beta that can be accessed via Beta releases. We would love for you to try these and share feedback with us before these features reach general availability (GA). To install a Beta version, please follow the [installation steps](#installation) above using the Beta release version.
61154

62-
We highly recommend keeping an eye on when the Beta feature you are interested in goes from Beta to stable so that you
63-
can move to using the stable version.
155+
> **Note:** there can be breaking changes between Beta versions. We recommend pinning the package version to a specific version.
64156
65157
## More Information
66158

67159
- [Single Sign-On Guide](https://workos.com/docs/sso/guide)
160+
- [User Management Guide](https://workos.com/docs/user-management)
161+
- [AuthKit Guide](https://workos.com/docs/authkit)
68162
- [Directory Sync Guide](https://workos.com/docs/directory-sync/guide)
69163
- [Admin Portal Guide](https://workos.com/docs/admin-portal/guide)
70-
- [Magic Link Guide](https://workos.com/docs/magic-link/guide)
164+
- [Audit Logs Guide](https://workos.com/docs/audit-logs)
165+
- [Authorization (FGA) Guide](https://workos.com/docs/fga)
166+
- [Feature Flags Guide](https://workos.com/docs/feature-flags)
167+
- [Webhooks Guide](https://workos.com/docs/webhooks)
168+
- [Radar Guide](https://workos.com/docs/radar)

0 commit comments

Comments
 (0)