fix: restore typed EventSchema discriminated union dispatcher#629
fix: restore typed EventSchema discriminated union dispatcher#629gjtorikian merged 5 commits intomainfrom
EventSchema discriminated union dispatcher#629Conversation
EventSchema.from_dict() now dispatches to the correct typed variant (e.g. DsyncUserCreated, UserCreated) based on the 'event' field, instead of returning a flat dataclass with data: Dict[str, Any]. list_events() and verify_event() return SyncPage[EventSchemaVariant] / AsyncPage[EventSchemaVariant] and EventSchemaVariant respectively, where EventSchemaVariant = Union[ActionAuthenticationDenied, ...] covers all 95 concrete event types with fully-typed data fields. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR restores typed event dispatching that was lost in the v5 upgrade. Confidence Score: 5/5This PR is safe to merge; no P0 or P1 issues found. All findings are P2 or lower. The dispatcher logic is correct: _raise_deserialize_error is NoReturn so there are no implicit None returns; each variant model's from_dict receives the full event dict as expected; unknown events gracefully fall back to EventSchemaUnknown; tests cover dispatch, unknown fallback, and error cases. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Raw event dict / webhook payload] --> B{EventSchema.from_dict}
B --> C{"'event' key present?"}
C -- No --> D[_raise_deserialize_error\nMissing required field]
C -- Yes --> E{"event value is None?"}
E -- Yes --> F[_raise_deserialize_error\nevent must not be None]
E -- No --> G{_DISPATCH.get\ndiscriminator value}
G -- Known key --> H[dispatch_cls.from_dict\ne.g. UserCreated, DsyncUserCreated]
G -- Unknown key --> I[EventSchemaUnknown.from_dict\nraw_data preserved]
H --> J[EventSchemaVariant]
I --> J
J --> K[list_events → SyncPage / AsyncPage]
J --> L[verify_event → EventSchemaVariant]
Reviews (5): Last reviewed commit: "fix: tighten event dispatch types and te..." | Re-trigger Greptile |
…rom_dict Raises a distinct "Missing required field 'event'" error when the key is absent, rather than falling through to the ambiguous "Unknown event: None" message. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptile review |
The `_DISPATCH` dict was typed as `Dict[str, Any]`, losing type safety on the class values. `EventSchemaVariant` was eagerly imported at runtime in `_verification.py` despite only being needed for type-checking annotations. Event list tests only checked page wrapper types without verifying that deserialization produces concrete event subclasses.
EventSchema discriminated union dispatcher
Summary
A user reported that the previous typed events in v5 were lost on the major upgrade. This PR restores them.
EventSchemais now a dispatcher class rather than a flat dataclass withdata: Dict[str, Any]EventSchema.from_dict()reads theeventfield and routes to the correct typed variant (e.g.DsyncUserCreated,UserCreated)EventSchemaVariant = Union[ActionAuthenticationDenied, ..., VaultNamesListed]covering all 95 event typesevents.list_events()returnsSyncPage[EventSchemaVariant]/AsyncPage[EventSchemaVariant]webhooks.verify_event()and_verification.verify_event()returnEventSchemaVariantEventSchemaremoved (dispatcher has noto_dict()); webhook verification fixture updated with a completeUserpayloadTest plan
uv run nox -s cipasses (1908 tests, lint, type check, format)workos.events.list_events()— each item is a fully-typed variant (e.g.DsyncUserCreatedwithdata: DirectoryUser)workos.webhooks.verify_event()— returns the correct variant for the event type in the payloadEventSchemaUnknownwith the raw payload preserved. Missing orNonediscriminator raisesWorkOSError.🤖 Generated with Claude Code