Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e24084e
style: fix ruff formatting in test_session.py
gjtorikian Mar 27, 2026
6033b93
chore: switch type checker from mypy to pyright strict
gjtorikian Mar 27, 2026
39e7c78
chore(deps): update dev dependencies (ruff, nox, nox-uv) (#601)
gjtorikian Mar 27, 2026
33e6aec
fix: resolve 38 pre-existing pyright errors in tests and fixtures
claude Mar 28, 2026
f2196c1
fix: set asyncio_default_fixture_loop_scope to silence deprecation wa…
claude Mar 28, 2026
6e0b60f
add `pytest-httpx` to `test` group
gjtorikian Mar 30, 2026
7184dd2
update dependencies
gjtorikian Mar 30, 2026
f57e7cc
swap mypy in lint CI for pyright
gjtorikian Mar 30, 2026
dab75bd
remove legacy types/, compat layer, and handwritten service modules
gjtorikian Mar 31, 2026
1516214
remove pydantic
gjtorikian Mar 31, 2026
fda2f5e
Rewrite CLAUDE.md
gjtorikian Mar 31, 2026
567c606
lock down `oagen-ignore` files
gjtorikian Mar 31, 2026
603f860
Add generated SDK modules with hand-maintained fixes
gjtorikian Mar 31, 2026
2e21112
lock cleanup
gjtorikian Mar 31, 2026
556cba6
format what needs formatting
gjtorikian Mar 31, 2026
62bb01e
remove these weird aliases
gjtorikian Mar 31, 2026
b6de8fc
drop compat layers
gjtorikian Mar 31, 2026
d78dc9d
restore some aliases
gjtorikian Mar 31, 2026
1be98d5
chore(python): regenerate sdk from updated emitter
gjtorikian Mar 31, 2026
b2b1fbf
fix: improve method names, restore timeout, add Event fields
gjtorikian Mar 31, 2026
58a7019
chore(python): regenerate SDK with empty-model pass fix
gjtorikian Mar 31, 2026
4138e96
chore(python): regenerate SDK with ignore-block class replacement fix
gjtorikian Mar 31, 2026
f62010c
chore(python): regenerate SDK with ignore-block and fixture fixes
gjtorikian Apr 1, 2026
901c70a
Regenerate client credential handling
gjtorikian Apr 1, 2026
ed07d10
Merge branch 'next-major' into oagen
gjtorikian Apr 1, 2026
f1f0d8f
initial migration guide
gjtorikian Apr 1, 2026
2d51bec
chore(python): regenerate SDK with exceptions and types backwards-compat
gjtorikian Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ jobs:
run: uv run ruff check --extend-exclude .devbox

- name: Type check
run: uv run mypy
run: uv run pyright
81 changes: 48 additions & 33 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

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

## Code Generation

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 (e.g., `session.py`, `passwordless.py`, `vault.py`).

## Development Commands

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

### Testing
Expand Down Expand Up @@ -69,50 +73,61 @@ bash scripts/build_and_upload_dist.sh # Build and upload to PyPI

The SDK provides both synchronous and asynchronous clients:

- `WorkOSClient` (sync) and `AsyncWorkOSClient` (async) are the main entry points
- Both inherit from `BaseClient` which handles configuration and module initialization
- Each feature area (SSO, Directory Sync, etc.) has dedicated module classes
- HTTP clients (`SyncHTTPClient`/`AsyncHTTPClient`) handle the actual API communication
- `WorkOS` (sync) and `AsyncWorkOS` (async) are the main entry points (exported from `workos/__init__.py`)
- Both inherit from `_BaseWorkOS` (in `workos/_client.py`) which handles configuration, HTTP transport, retry logic, and error mapping
- Each feature area (SSO, Organizations, etc.) is exposed as a `@functools.cached_property` on the client for lazy loading
- Complex feature areas use namespace classes (e.g., `UserManagementNamespace`, `OrganizationsNamespace`) to group sub-resources
- Backward-compatible aliases exist: `WorkOSClient = WorkOS`, `AsyncWorkOSClient = AsyncWorkOS`
- HTTP transport uses `httpx` directly; there is no separate HTTP client abstraction layer

### Module Structure

Each WorkOS feature has its own module following this pattern:
Each feature module follows this layout:

```
src/workos/{module_name}/
__init__.py # Re-exports from _resource and models
_resource.py # Sync and Async resource classes (e.g., SSO + AsyncSSO)
models/
__init__.py # Re-exports all model classes
{model}.py # Individual dataclass model files
```

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

### Type System

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

### Testing Framework
### Pagination

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

### HTTP Client Abstraction
### Error Handling

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

### Key Patterns
- `BadRequestError` (400), `AuthenticationError` (401), `ForbiddenError` (403), `NotFoundError` (404), `ConflictError` (409), `UnprocessableEntityError` (422), `RateLimitExceededError` (429), `ServerError` (5xx)
- `ConfigurationError`, `WorkOSConnectionError`, `WorkOSTimeoutError` for non-HTTP errors
- `STATUS_CODE_TO_ERROR` dict maps status codes to exception classes

### Testing Framework

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

When adding new features:
### Configuration

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