From 4914c8d7f3e3a6aa4b15a1618286696f5ae437f5 Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 20:02:53 +0000 Subject: [PATCH] feat(generated): Add new event types and user object to membership models --- .last-synced-sha | 2 +- .oagen-manifest.json | 20 +- src/workos/api_keys/models/__init__.py | 6 + src/workos/api_keys/models/api_key.py | 2 +- .../models/api_key_validation_response.py | 8 +- .../api_key_validation_response_api_key.py | 6 + ...i_key_validation_response_api_key_owner.py | 6 + src/workos/authorization/_resource.py | 26 +- src/workos/authorization/models/__init__.py | 4 +- ..._organization_membership_base_with_user.py | 86 ++ src/workos/common/__init__.py | 7 + src/workos/common/models/__init__.py | 7 + .../models/api_key_created_data_owner.py | 2 +- src/workos/common/models/directory_user.py | 7 + .../common/models/dsync_token_created.py | 60 ++ .../common/models/dsync_token_created_data.py | 63 ++ .../common/models/dsync_token_deleted.py | 60 ++ .../common/models/dsync_token_deleted_data.py | 6 + .../common/models/dsync_user_updated_data.py | 7 + .../models/event_context_actor_source.py | 5 +- ...zation_membership_base_with_user_status.py | 11 + .../models/directory_user_with_groups.py | 9 +- src/workos/events/models/event_schema.py | 6 + src/workos/groups/_resource.py | 5 +- src/workos/groups/models/__init__.py | 3 + ..._organization_membership_base_list_data.py | 0 src/workos/sso/models/profile.py | 7 + .../models/organization_membership.py | 5 + .../api_key_validation_response_api_key.json | 17 + ...key_validation_response_api_key_owner.json | 4 + tests/fixtures/directory_user.json | 1 + .../fixtures/directory_user_with_groups.json | 1 + tests/fixtures/dsync_group_user_added.json | 1 + .../fixtures/dsync_group_user_added_data.json | 1 + tests/fixtures/dsync_group_user_removed.json | 1 + .../dsync_group_user_removed_data.json | 1 + tests/fixtures/dsync_token_created.json | 35 + tests/fixtures/dsync_token_created_data.json | 9 + tests/fixtures/dsync_token_deleted.json | 35 + tests/fixtures/dsync_token_deleted_data.json | 9 + tests/fixtures/dsync_user_created.json | 1 + tests/fixtures/dsync_user_deleted.json | 1 + tests/fixtures/dsync_user_updated.json | 1 + tests/fixtures/dsync_user_updated_data.json | 1 + tests/fixtures/jwt_template_response.json | 2 +- .../list_directory_user_with_groups.json | 1 + .../list_user_organization_membership.json | 19 +- ...rganization_membership_base_list_data.json | 2 +- ...rganization_membership_base_with_user.json | 41 + tests/fixtures/organization_membership.json | 17 + tests/fixtures/profile.json | 1 + tests/fixtures/sso_token_response.json | 1 + tests/fixtures/update_jwt_template.json | 2 +- .../user_organization_membership.json | 19 +- ...rganization_membership_base_list_data.json | 2 +- ...rganization_membership_base_with_user.json | 33 + tests/test_authorization.py | 18 +- tests/test_groups.py | 7 +- tests/test_models_round_trip.py | 981 +++++++++++++----- 59 files changed, 1424 insertions(+), 277 deletions(-) create mode 100644 src/workos/api_keys/models/api_key_validation_response_api_key.py create mode 100644 src/workos/api_keys/models/api_key_validation_response_api_key_owner.py create mode 100644 src/workos/authorization/models/user_organization_membership_base_with_user.py create mode 100644 src/workos/common/models/dsync_token_created.py create mode 100644 src/workos/common/models/dsync_token_created_data.py create mode 100644 src/workos/common/models/dsync_token_deleted.py create mode 100644 src/workos/common/models/dsync_token_deleted_data.py create mode 100644 src/workos/common/models/user_organization_membership_base_with_user_status.py rename src/workos/{authorization => groups}/models/user_organization_membership_base_list_data.py (100%) create mode 100644 tests/fixtures/api_key_validation_response_api_key.json create mode 100644 tests/fixtures/api_key_validation_response_api_key_owner.json create mode 100644 tests/fixtures/dsync_token_created.json create mode 100644 tests/fixtures/dsync_token_created_data.json create mode 100644 tests/fixtures/dsync_token_deleted.json create mode 100644 tests/fixtures/dsync_token_deleted_data.json create mode 100644 tests/fixtures/list_user_organization_membership_base_with_user.json create mode 100644 tests/fixtures/user_organization_membership_base_with_user.json diff --git a/.last-synced-sha b/.last-synced-sha index f72eb0e2..be98ab48 100644 --- a/.last-synced-sha +++ b/.last-synced-sha @@ -1 +1 @@ -92db0495807c86fbbc4d45bd266a6c1f5bcbb59c +f908f520f9fcd63dfd42ed35b7f141a65b61609b diff --git a/.oagen-manifest.json b/.oagen-manifest.json index fa3d1ee4..c500d75b 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -1,7 +1,7 @@ { "version": 2, "language": "python", - "generatedAt": "2026-04-28T16:15:39.420Z", + "generatedAt": "2026-04-30T20:02:46.665Z", "files": [ "src/workos/_client.py", "src/workos/admin_portal/__init__.py", @@ -18,6 +18,8 @@ "src/workos/api_keys/models/api_key.py", "src/workos/api_keys/models/api_key_owner.py", "src/workos/api_keys/models/api_key_validation_response.py", + "src/workos/api_keys/models/api_key_validation_response_api_key.py", + "src/workos/api_keys/models/api_key_validation_response_api_key_owner.py", "src/workos/api_keys/models/api_key_with_value.py", "src/workos/api_keys/models/api_key_with_value_owner.py", "src/workos/api_keys/models/create_organization_api_key.py", @@ -70,7 +72,7 @@ "src/workos/authorization/models/update_authorization_resource.py", "src/workos/authorization/models/update_organization_role.py", "src/workos/authorization/models/update_role.py", - "src/workos/authorization/models/user_organization_membership_base_list_data.py", + "src/workos/authorization/models/user_organization_membership_base_with_user.py", "src/workos/common/__init__.py", "src/workos/common/models/__init__.py", "src/workos/common/models/action_authentication_denied.py", @@ -202,6 +204,10 @@ "src/workos/common/models/dsync_group_user_added_data.py", "src/workos/common/models/dsync_group_user_removed.py", "src/workos/common/models/dsync_group_user_removed_data.py", + "src/workos/common/models/dsync_token_created.py", + "src/workos/common/models/dsync_token_created_data.py", + "src/workos/common/models/dsync_token_deleted.py", + "src/workos/common/models/dsync_token_deleted_data.py", "src/workos/common/models/dsync_user_created.py", "src/workos/common/models/dsync_user_deleted.py", "src/workos/common/models/dsync_user_updated.py", @@ -374,6 +380,7 @@ "src/workos/common/models/user_identities_get_item_provider.py", "src/workos/common/models/user_invite_state.py", "src/workos/common/models/user_organization_membership_base_list_data_status.py", + "src/workos/common/models/user_organization_membership_base_with_user_status.py", "src/workos/common/models/user_organization_membership_status.py", "src/workos/common/models/user_sessions_auth_method.py", "src/workos/common/models/user_sessions_status.py", @@ -468,6 +475,7 @@ "src/workos/groups/models/group.py", "src/workos/groups/models/groups_order.py", "src/workos/groups/models/update_group.py", + "src/workos/groups/models/user_organization_membership_base_list_data.py", "src/workos/multi_factor_auth/__init__.py", "src/workos/multi_factor_auth/_resource.py", "src/workos/multi_factor_auth/models/__init__.py", @@ -654,6 +662,8 @@ "tests/fixtures/api_key_revoked_data.json", "tests/fixtures/api_key_revoked_data_owner.json", "tests/fixtures/api_key_validation_response.json", + "tests/fixtures/api_key_validation_response_api_key.json", + "tests/fixtures/api_key_validation_response_api_key_owner.json", "tests/fixtures/api_key_with_value.json", "tests/fixtures/api_key_with_value_owner.json", "tests/fixtures/application_credentials_list_item.json", @@ -819,6 +829,10 @@ "tests/fixtures/dsync_group_user_added_data.json", "tests/fixtures/dsync_group_user_removed.json", "tests/fixtures/dsync_group_user_removed_data.json", + "tests/fixtures/dsync_token_created.json", + "tests/fixtures/dsync_token_created_data.json", + "tests/fixtures/dsync_token_deleted.json", + "tests/fixtures/dsync_token_deleted_data.json", "tests/fixtures/dsync_user_created.json", "tests/fixtures/dsync_user_deleted.json", "tests/fixtures/dsync_user_updated.json", @@ -916,6 +930,7 @@ "tests/fixtures/list_user_invite.json", "tests/fixtures/list_user_organization_membership.json", "tests/fixtures/list_user_organization_membership_base_list_data.json", + "tests/fixtures/list_user_organization_membership_base_with_user.json", "tests/fixtures/list_user_sessions_list_item.json", "tests/fixtures/list_webhook_endpoint_json.json", "tests/fixtures/magic_auth.json", @@ -1043,6 +1058,7 @@ "tests/fixtures/user_object.json", "tests/fixtures/user_organization_membership.json", "tests/fixtures/user_organization_membership_base_list_data.json", + "tests/fixtures/user_organization_membership_base_with_user.json", "tests/fixtures/user_sessions_impersonator.json", "tests/fixtures/user_sessions_list_item.json", "tests/fixtures/user_updated.json", diff --git a/src/workos/api_keys/models/__init__.py b/src/workos/api_keys/models/__init__.py index 86ecd07b..55427274 100644 --- a/src/workos/api_keys/models/__init__.py +++ b/src/workos/api_keys/models/__init__.py @@ -5,6 +5,12 @@ from .api_key_validation_response import ( ApiKeyValidationResponse as ApiKeyValidationResponse, ) +from .api_key_validation_response_api_key import ( + ApiKeyValidationResponseApiKey as ApiKeyValidationResponseApiKey, +) +from .api_key_validation_response_api_key_owner import ( + ApiKeyValidationResponseApiKeyOwner as ApiKeyValidationResponseApiKeyOwner, +) from .api_key_with_value import ApiKeyWithValue as ApiKeyWithValue from .api_key_with_value_owner import ApiKeyWithValueOwner as ApiKeyWithValueOwner from .create_organization_api_key import ( diff --git a/src/workos/api_keys/models/api_key.py b/src/workos/api_keys/models/api_key.py index c59bbf72..fb19da8d 100644 --- a/src/workos/api_keys/models/api_key.py +++ b/src/workos/api_keys/models/api_key.py @@ -14,7 +14,7 @@ @dataclass(slots=True) class ApiKey: - """The API Key object if the value is valid, or `null` if invalid.""" + """Api Key model.""" object: Literal["api_key"] """Distinguishes the API Key object.""" diff --git a/src/workos/api_keys/models/api_key_validation_response.py b/src/workos/api_keys/models/api_key_validation_response.py index 0dc28eb2..79f1f945 100644 --- a/src/workos/api_keys/models/api_key_validation_response.py +++ b/src/workos/api_keys/models/api_key_validation_response.py @@ -7,21 +7,23 @@ from typing import Any, Dict, Optional from workos._types import _raise_deserialize_error -from .api_key import ApiKey +from .api_key_validation_response_api_key import ApiKeyValidationResponseApiKey @dataclass(slots=True) class ApiKeyValidationResponse: """Api Key Validation Response model.""" - api_key: Optional["ApiKey"] + api_key: Optional["ApiKeyValidationResponseApiKey"] @classmethod def from_dict(cls, data: Dict[str, Any]) -> "ApiKeyValidationResponse": """Deserialize from a dictionary.""" try: return cls( - api_key=ApiKey.from_dict(cast(Dict[str, Any], _v_api_key)) + api_key=ApiKeyValidationResponseApiKey.from_dict( + cast(Dict[str, Any], _v_api_key) + ) if (_v_api_key := data["api_key"]) is not None else None, ) diff --git a/src/workos/api_keys/models/api_key_validation_response_api_key.py b/src/workos/api_keys/models/api_key_validation_response_api_key.py new file mode 100644 index 00000000..f6cb8c13 --- /dev/null +++ b/src/workos/api_keys/models/api_key_validation_response_api_key.py @@ -0,0 +1,6 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias +from .api_key import ApiKey + +ApiKeyValidationResponseApiKey: TypeAlias = ApiKey diff --git a/src/workos/api_keys/models/api_key_validation_response_api_key_owner.py b/src/workos/api_keys/models/api_key_validation_response_api_key_owner.py new file mode 100644 index 00000000..01d48b1a --- /dev/null +++ b/src/workos/api_keys/models/api_key_validation_response_api_key_owner.py @@ -0,0 +1,6 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias +from workos.common.models.api_key_created_data_owner import ApiKeyCreatedDataOwner + +ApiKeyValidationResponseApiKeyOwner: TypeAlias = ApiKeyCreatedDataOwner diff --git a/src/workos/authorization/_resource.py b/src/workos/authorization/_resource.py index 55a229c8..b58ad33a 100644 --- a/src/workos/authorization/_resource.py +++ b/src/workos/authorization/_resource.py @@ -16,7 +16,7 @@ Role, RoleAssignment, RoleList, - UserOrganizationMembershipBaseListData, + UserOrganizationMembershipBaseWithUser, ) from .models import AuthorizationAssignment, AuthorizationOrder, PermissionsOrder from .._pagination import AsyncPage, SyncPage @@ -924,7 +924,7 @@ def list_memberships_for_resource_by_external_id( permission_slug: str, assignment: Optional[Union[AuthorizationAssignment, str]] = None, request_options: Optional[RequestOptions] = None, - ) -> SyncPage[UserOrganizationMembershipBaseListData]: + ) -> SyncPage[UserOrganizationMembershipBaseWithUser]: """List memberships for a resource by external ID Returns all organization memberships that have a specific permission on a resource, using the resource's external ID. This is useful for answering "Who can access this resource?" when you only have the external ID. @@ -942,7 +942,7 @@ def list_memberships_for_resource_by_external_id( request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: - SyncPage[UserOrganizationMembershipBaseListData] + SyncPage[UserOrganizationMembershipBaseWithUser] Raises: BadRequestError: If the request is malformed (400). @@ -970,7 +970,7 @@ def list_memberships_for_resource_by_external_id( return self._client.request_page( method="get", path=f"authorization/organizations/{organization_id}/resources/{resource_type_slug}/{external_id}/organization_memberships", - model=UserOrganizationMembershipBaseListData, + model=UserOrganizationMembershipBaseWithUser, params=params, request_options=request_options, ) @@ -1254,7 +1254,7 @@ def list_memberships_for_resource( permission_slug: str, assignment: Optional[Union[AuthorizationAssignment, str]] = None, request_options: Optional[RequestOptions] = None, - ) -> SyncPage[UserOrganizationMembershipBaseListData]: + ) -> SyncPage[UserOrganizationMembershipBaseWithUser]: """List organization memberships for resource Returns all organization memberships that have a specific permission on a resource instance. This is useful for answering "Who can access this resource?". @@ -1270,7 +1270,7 @@ def list_memberships_for_resource( request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: - SyncPage[UserOrganizationMembershipBaseListData] + SyncPage[UserOrganizationMembershipBaseWithUser] Raises: BadRequestError: If the request is malformed (400). @@ -1298,7 +1298,7 @@ def list_memberships_for_resource( return self._client.request_page( method="get", path=f"authorization/resources/{resource_id}/organization_memberships", - model=UserOrganizationMembershipBaseListData, + model=UserOrganizationMembershipBaseWithUser, params=params, request_options=request_options, ) @@ -2590,7 +2590,7 @@ async def list_memberships_for_resource_by_external_id( permission_slug: str, assignment: Optional[Union[AuthorizationAssignment, str]] = None, request_options: Optional[RequestOptions] = None, - ) -> AsyncPage[UserOrganizationMembershipBaseListData]: + ) -> AsyncPage[UserOrganizationMembershipBaseWithUser]: """List memberships for a resource by external ID Returns all organization memberships that have a specific permission on a resource, using the resource's external ID. This is useful for answering "Who can access this resource?" when you only have the external ID. @@ -2608,7 +2608,7 @@ async def list_memberships_for_resource_by_external_id( request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: - AsyncPage[UserOrganizationMembershipBaseListData] + AsyncPage[UserOrganizationMembershipBaseWithUser] Raises: BadRequestError: If the request is malformed (400). @@ -2636,7 +2636,7 @@ async def list_memberships_for_resource_by_external_id( return await self._client.request_page( method="get", path=f"authorization/organizations/{organization_id}/resources/{resource_type_slug}/{external_id}/organization_memberships", - model=UserOrganizationMembershipBaseListData, + model=UserOrganizationMembershipBaseWithUser, params=params, request_options=request_options, ) @@ -2920,7 +2920,7 @@ async def list_memberships_for_resource( permission_slug: str, assignment: Optional[Union[AuthorizationAssignment, str]] = None, request_options: Optional[RequestOptions] = None, - ) -> AsyncPage[UserOrganizationMembershipBaseListData]: + ) -> AsyncPage[UserOrganizationMembershipBaseWithUser]: """List organization memberships for resource Returns all organization memberships that have a specific permission on a resource instance. This is useful for answering "Who can access this resource?". @@ -2936,7 +2936,7 @@ async def list_memberships_for_resource( request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: - AsyncPage[UserOrganizationMembershipBaseListData] + AsyncPage[UserOrganizationMembershipBaseWithUser] Raises: BadRequestError: If the request is malformed (400). @@ -2964,7 +2964,7 @@ async def list_memberships_for_resource( return await self._client.request_page( method="get", path=f"authorization/resources/{resource_id}/organization_memberships", - model=UserOrganizationMembershipBaseListData, + model=UserOrganizationMembershipBaseWithUser, params=params, request_options=request_options, ) diff --git a/src/workos/authorization/models/__init__.py b/src/workos/authorization/models/__init__.py index 6e303bff..09039daa 100644 --- a/src/workos/authorization/models/__init__.py +++ b/src/workos/authorization/models/__init__.py @@ -33,6 +33,6 @@ ) from .update_organization_role import UpdateOrganizationRole as UpdateOrganizationRole from .update_role import UpdateRole as UpdateRole -from .user_organization_membership_base_list_data import ( - UserOrganizationMembershipBaseListData as UserOrganizationMembershipBaseListData, +from .user_organization_membership_base_with_user import ( + UserOrganizationMembershipBaseWithUser as UserOrganizationMembershipBaseWithUser, ) diff --git a/src/workos/authorization/models/user_organization_membership_base_with_user.py b/src/workos/authorization/models/user_organization_membership_base_with_user.py new file mode 100644 index 00000000..b5a6c861 --- /dev/null +++ b/src/workos/authorization/models/user_organization_membership_base_with_user.py @@ -0,0 +1,86 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import cast +from typing import Any, Dict, Literal, Optional +from workos._types import _raise_deserialize_error +from workos._types import _format_datetime, _parse_datetime + +from workos.user_management.models.user import User +from workos.common.models.user_organization_membership_base_with_user_status import ( + UserOrganizationMembershipBaseWithUserStatus, +) + + +@dataclass(slots=True) +class UserOrganizationMembershipBaseWithUser: + """User Organization Membership Base With User model.""" + + object: Literal["organization_membership"] + """Distinguishes the organization membership object.""" + id: str + """The unique ID of the organization membership.""" + user_id: str + """The ID of the user.""" + organization_id: str + """The ID of the organization which the user belongs to.""" + status: "UserOrganizationMembershipBaseWithUserStatus" + """The status of the organization membership. One of `active`, `inactive`, or `pending`.""" + directory_managed: bool + """Whether this organization membership is managed by a directory sync connection.""" + created_at: datetime + """An ISO 8601 timestamp.""" + updated_at: datetime + """An ISO 8601 timestamp.""" + user: "User" + """The user that belongs to the organization through this membership.""" + organization_name: Optional[str] = None + """The name of the organization which the user belongs to.""" + custom_attributes: Optional[Dict[str, Any]] = None + """An object containing IdP-sourced attributes from the linked [Directory User](https://workos.com/docs/reference/directory-sync/directory-user) or [SSO Profile](https://workos.com/docs/reference/sso/profile). Directory User attributes take precedence when both are linked.""" + + @classmethod + def from_dict( + cls, data: Dict[str, Any] + ) -> "UserOrganizationMembershipBaseWithUser": + """Deserialize from a dictionary.""" + try: + return cls( + object=data.get("object", "organization_membership"), + id=data["id"], + user_id=data["user_id"], + organization_id=data["organization_id"], + status=UserOrganizationMembershipBaseWithUserStatus(data["status"]), + directory_managed=data["directory_managed"], + created_at=_parse_datetime(data["created_at"]), + updated_at=_parse_datetime(data["updated_at"]), + user=User.from_dict(cast(Dict[str, Any], data["user"])), + organization_name=data.get("organization_name"), + custom_attributes=data.get("custom_attributes"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("UserOrganizationMembershipBaseWithUser", e) + + def to_dict(self) -> Dict[str, Any]: + """Serialize to a dictionary.""" + result: Dict[str, Any] = {} + result["object"] = self.object + result["id"] = self.id + result["user_id"] = self.user_id + result["organization_id"] = self.organization_id + result["status"] = ( + self.status.value if isinstance(self.status, Enum) else self.status + ) + result["directory_managed"] = self.directory_managed + result["created_at"] = _format_datetime(self.created_at) + result["updated_at"] = _format_datetime(self.updated_at) + result["user"] = self.user.to_dict() + if self.organization_name is not None: + result["organization_name"] = self.organization_name + if self.custom_attributes is not None: + result["custom_attributes"] = self.custom_attributes + return result diff --git a/src/workos/common/__init__.py b/src/workos/common/__init__.py index 8d5ff562..180ddfce 100644 --- a/src/workos/common/__init__.py +++ b/src/workos/common/__init__.py @@ -171,6 +171,10 @@ from .models import DsyncGroupUserAddedData as DsyncGroupUserAddedData from .models import DsyncGroupUserRemoved as DsyncGroupUserRemoved from .models import DsyncGroupUserRemovedData as DsyncGroupUserRemovedData +from .models import DsyncTokenCreated as DsyncTokenCreated +from .models import DsyncTokenCreatedData as DsyncTokenCreatedData +from .models import DsyncTokenDeleted as DsyncTokenDeleted +from .models import DsyncTokenDeletedData as DsyncTokenDeletedData from .models import DsyncUserCreated as DsyncUserCreated from .models import DsyncUserDeleted as DsyncUserDeleted from .models import DsyncUserUpdated as DsyncUserUpdated @@ -357,6 +361,9 @@ from .models import ( UserOrganizationMembershipBaseListDataStatus as UserOrganizationMembershipBaseListDataStatus, ) +from .models import ( + UserOrganizationMembershipBaseWithUserStatus as UserOrganizationMembershipBaseWithUserStatus, +) from .models import UserOrganizationMembershipStatus as UserOrganizationMembershipStatus from .models import UserSessionsAuthMethod as UserSessionsAuthMethod from .models import UserSessionsStatus as UserSessionsStatus diff --git a/src/workos/common/models/__init__.py b/src/workos/common/models/__init__.py index f27d1492..bcc05b07 100644 --- a/src/workos/common/models/__init__.py +++ b/src/workos/common/models/__init__.py @@ -273,6 +273,10 @@ from .dsync_group_user_removed_data import ( DsyncGroupUserRemovedData as DsyncGroupUserRemovedData, ) +from .dsync_token_created import DsyncTokenCreated as DsyncTokenCreated +from .dsync_token_created_data import DsyncTokenCreatedData as DsyncTokenCreatedData +from .dsync_token_deleted import DsyncTokenDeleted as DsyncTokenDeleted +from .dsync_token_deleted_data import DsyncTokenDeletedData as DsyncTokenDeletedData from .dsync_user_created import DsyncUserCreated as DsyncUserCreated from .dsync_user_deleted import DsyncUserDeleted as DsyncUserDeleted from .dsync_user_updated import DsyncUserUpdated as DsyncUserUpdated @@ -549,6 +553,9 @@ from .user_organization_membership_base_list_data_status import ( UserOrganizationMembershipBaseListDataStatus as UserOrganizationMembershipBaseListDataStatus, ) +from .user_organization_membership_base_with_user_status import ( + UserOrganizationMembershipBaseWithUserStatus as UserOrganizationMembershipBaseWithUserStatus, +) from .user_organization_membership_status import ( UserOrganizationMembershipStatus as UserOrganizationMembershipStatus, ) diff --git a/src/workos/common/models/api_key_created_data_owner.py b/src/workos/common/models/api_key_created_data_owner.py index df51ebf1..e99edf06 100644 --- a/src/workos/common/models/api_key_created_data_owner.py +++ b/src/workos/common/models/api_key_created_data_owner.py @@ -9,7 +9,7 @@ @dataclass(slots=True) class ApiKeyCreatedDataOwner: - """The owner of the API key.""" + """Api Key Created Data Owner model.""" type: Literal["organization"] """The type of the API key owner.""" diff --git a/src/workos/common/models/directory_user.py b/src/workos/common/models/directory_user.py index 37772c9f..056d8ec8 100644 --- a/src/workos/common/models/directory_user.py +++ b/src/workos/common/models/directory_user.py @@ -43,6 +43,8 @@ class DirectoryUser: """The first name of the user.""" last_name: Optional[str] = None """The last name of the user.""" + name: Optional[str] = None + """The full name of the user.""" emails: Optional[List["DirectoryUserEmail"]] = None """A list of email addresses for the user. @@ -80,6 +82,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "DirectoryUser": updated_at=_parse_datetime(data["updated_at"]), first_name=data.get("first_name"), last_name=data.get("last_name"), + name=data.get("name"), emails=[ DirectoryUserEmail.from_dict(cast(Dict[str, Any], item)) for item in cast(list[Any], _v_emails) @@ -128,6 +131,10 @@ def to_dict(self) -> Dict[str, Any]: result["last_name"] = self.last_name else: result["last_name"] = None + if self.name is not None: + result["name"] = self.name + else: + result["name"] = None if self.emails is not None: result["emails"] = [item.to_dict() for item in self.emails] if self.job_title is not None: diff --git a/src/workos/common/models/dsync_token_created.py b/src/workos/common/models/dsync_token_created.py new file mode 100644 index 00000000..002100ad --- /dev/null +++ b/src/workos/common/models/dsync_token_created.py @@ -0,0 +1,60 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from typing import cast +from typing import Any, Dict, Literal, Optional +from workos._types import _raise_deserialize_error +from workos._types import _format_datetime, _parse_datetime + +from .dsync_token_created_data import DsyncTokenCreatedData +from .event_context import EventContext + + +@dataclass(slots=True) +class DsyncTokenCreated: + """Dsync Token Created model.""" + + id: str + """Unique identifier for the event.""" + event: Literal["dsync.token.created"] + data: "DsyncTokenCreatedData" + """The event payload.""" + created_at: datetime + """An ISO 8601 timestamp.""" + object: Literal["event"] + """Distinguishes the Event object.""" + context: Optional["EventContext"] = None + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DsyncTokenCreated": + """Deserialize from a dictionary.""" + try: + return cls( + id=data["id"], + event=data.get("event", "dsync.token.created"), + data=DsyncTokenCreatedData.from_dict( + cast(Dict[str, Any], data["data"]) + ), + created_at=_parse_datetime(data["created_at"]), + object=data.get("object", "event"), + context=EventContext.from_dict(cast(Dict[str, Any], _v_context)) + if (_v_context := data.get("context")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("DsyncTokenCreated", e) + + def to_dict(self) -> Dict[str, Any]: + """Serialize to a dictionary.""" + result: Dict[str, Any] = {} + result["id"] = self.id + result["event"] = self.event + result["data"] = self.data.to_dict() + result["created_at"] = _format_datetime(self.created_at) + result["object"] = self.object + if self.context is not None: + result["context"] = self.context.to_dict() + return result diff --git a/src/workos/common/models/dsync_token_created_data.py b/src/workos/common/models/dsync_token_created_data.py new file mode 100644 index 00000000..71c45c0f --- /dev/null +++ b/src/workos/common/models/dsync_token_created_data.py @@ -0,0 +1,63 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from typing import Any, Dict, Literal, Optional +from workos._types import _raise_deserialize_error +from workos._types import _format_datetime, _parse_datetime + + +@dataclass(slots=True) +class DsyncTokenCreatedData: + """The event payload.""" + + object: Literal["directory_token"] + """Distinguishes the directory token object.""" + id: str + """Unique identifier of the directory token.""" + directory_id: str + """The ID of the directory the token authenticates to.""" + token_suffix: str + """The trailing characters of the bearer token, for identification only. The full token value is never included in events.""" + created_at: datetime + """An ISO 8601 timestamp.""" + expires_at: Optional[datetime] + """The timestamp at which the token expires, or null for tokens without a scheduled expiration. Used during rotation to indicate the grace window for the outgoing token.""" + organization_id: Optional[str] = None + """The ID of the organization the directory belongs to.""" + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DsyncTokenCreatedData": + """Deserialize from a dictionary.""" + try: + return cls( + object=data.get("object", "directory_token"), + id=data["id"], + directory_id=data["directory_id"], + token_suffix=data["token_suffix"], + created_at=_parse_datetime(data["created_at"]), + expires_at=_parse_datetime(_v_expires_at) + if (_v_expires_at := data["expires_at"]) is not None + else None, + organization_id=data.get("organization_id"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("DsyncTokenCreatedData", e) + + def to_dict(self) -> Dict[str, Any]: + """Serialize to a dictionary.""" + result: Dict[str, Any] = {} + result["object"] = self.object + result["id"] = self.id + result["directory_id"] = self.directory_id + result["token_suffix"] = self.token_suffix + result["created_at"] = _format_datetime(self.created_at) + if self.expires_at is not None: + result["expires_at"] = _format_datetime(self.expires_at) + else: + result["expires_at"] = None + if self.organization_id is not None: + result["organization_id"] = self.organization_id + return result diff --git a/src/workos/common/models/dsync_token_deleted.py b/src/workos/common/models/dsync_token_deleted.py new file mode 100644 index 00000000..c2029819 --- /dev/null +++ b/src/workos/common/models/dsync_token_deleted.py @@ -0,0 +1,60 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from typing import cast +from typing import Any, Dict, Literal, Optional +from workos._types import _raise_deserialize_error +from workos._types import _format_datetime, _parse_datetime + +from .dsync_token_deleted_data import DsyncTokenDeletedData +from .event_context import EventContext + + +@dataclass(slots=True) +class DsyncTokenDeleted: + """Dsync Token Deleted model.""" + + id: str + """Unique identifier for the event.""" + event: Literal["dsync.token.deleted"] + data: "DsyncTokenDeletedData" + """The event payload.""" + created_at: datetime + """An ISO 8601 timestamp.""" + object: Literal["event"] + """Distinguishes the Event object.""" + context: Optional["EventContext"] = None + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DsyncTokenDeleted": + """Deserialize from a dictionary.""" + try: + return cls( + id=data["id"], + event=data.get("event", "dsync.token.deleted"), + data=DsyncTokenDeletedData.from_dict( + cast(Dict[str, Any], data["data"]) + ), + created_at=_parse_datetime(data["created_at"]), + object=data.get("object", "event"), + context=EventContext.from_dict(cast(Dict[str, Any], _v_context)) + if (_v_context := data.get("context")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("DsyncTokenDeleted", e) + + def to_dict(self) -> Dict[str, Any]: + """Serialize to a dictionary.""" + result: Dict[str, Any] = {} + result["id"] = self.id + result["event"] = self.event + result["data"] = self.data.to_dict() + result["created_at"] = _format_datetime(self.created_at) + result["object"] = self.object + if self.context is not None: + result["context"] = self.context.to_dict() + return result diff --git a/src/workos/common/models/dsync_token_deleted_data.py b/src/workos/common/models/dsync_token_deleted_data.py new file mode 100644 index 00000000..52de3d64 --- /dev/null +++ b/src/workos/common/models/dsync_token_deleted_data.py @@ -0,0 +1,6 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias +from .dsync_token_created_data import DsyncTokenCreatedData + +DsyncTokenDeletedData: TypeAlias = DsyncTokenCreatedData diff --git a/src/workos/common/models/dsync_user_updated_data.py b/src/workos/common/models/dsync_user_updated_data.py index 90956d01..29a78971 100644 --- a/src/workos/common/models/dsync_user_updated_data.py +++ b/src/workos/common/models/dsync_user_updated_data.py @@ -43,6 +43,8 @@ class DsyncUserUpdatedData: """The first name of the user.""" last_name: Optional[str] = None """The last name of the user.""" + name: Optional[str] = None + """The full name of the user.""" emails: Optional[List["DsyncUserUpdatedDataEmail"]] = None """A list of email addresses for the user. @@ -81,6 +83,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "DsyncUserUpdatedData": updated_at=_parse_datetime(data["updated_at"]), first_name=data.get("first_name"), last_name=data.get("last_name"), + name=data.get("name"), emails=[ DsyncUserUpdatedDataEmail.from_dict(cast(Dict[str, Any], item)) for item in cast(list[Any], _v_emails) @@ -130,6 +133,10 @@ def to_dict(self) -> Dict[str, Any]: result["last_name"] = self.last_name else: result["last_name"] = None + if self.name is not None: + result["name"] = self.name + else: + result["name"] = None if self.emails is not None: result["emails"] = [item.to_dict() for item in self.emails] if self.job_title is not None: diff --git a/src/workos/common/models/event_context_actor_source.py b/src/workos/common/models/event_context_actor_source.py index f270625e..a70e58e7 100644 --- a/src/workos/common/models/event_context_actor_source.py +++ b/src/workos/common/models/event_context_actor_source.py @@ -14,6 +14,7 @@ class EventContextActorSource(str, Enum): API = "api" DASHBOARD = "dashboard" + ADMIN_PORTAL = "admin_portal" SYSTEM = "system" @classmethod @@ -26,4 +27,6 @@ def _missing_(cls, value: object) -> Optional["EventContextActorSource"]: return unknown -EventContextActorSourceLiteral: TypeAlias = Literal["api", "dashboard", "system"] +EventContextActorSourceLiteral: TypeAlias = Literal[ + "api", "dashboard", "admin_portal", "system" +] diff --git a/src/workos/common/models/user_organization_membership_base_with_user_status.py b/src/workos/common/models/user_organization_membership_base_with_user_status.py new file mode 100644 index 00000000..c22989b3 --- /dev/null +++ b/src/workos/common/models/user_organization_membership_base_with_user_status.py @@ -0,0 +1,11 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias +from .organization_membership_created_data_status import ( + OrganizationMembershipCreatedDataStatus, +) + +UserOrganizationMembershipBaseWithUserStatus: TypeAlias = ( + OrganizationMembershipCreatedDataStatus +) +__all__ = ["UserOrganizationMembershipBaseWithUserStatus"] diff --git a/src/workos/directory_sync/models/directory_user_with_groups.py b/src/workos/directory_sync/models/directory_user_with_groups.py index 58be6a89..764c55fe 100644 --- a/src/workos/directory_sync/models/directory_user_with_groups.py +++ b/src/workos/directory_sync/models/directory_user_with_groups.py @@ -46,6 +46,8 @@ class DirectoryUserWithGroups: """The first name of the user.""" last_name: Optional[str] = None """The last name of the user.""" + name: Optional[str] = None + """The full name of the user.""" emails: Optional[List["DirectoryUserWithGroupsEmail"]] = None """A list of email addresses for the user. @@ -66,7 +68,7 @@ class DirectoryUserWithGroups: roles: Optional[List["SlimRole"]] = None """All roles assigned to the user.""" groups: Optional[List["DirectoryGroup"]] = None - """The directory groups the user belongs to. Use the List Directory Groups endpoint with a user filter instead. + """The directory groups the user belongs to. Deprecated: starting May 1, 2026, this field returns an empty array by default for newly created teams. Existing teams currently depending on this field should migrate to the new access pattern for better throughput performance — the field is unbounded by user, so users with many group memberships produce large, slow response payloads. Use the List Directory Groups endpoint with a `user` filter to fetch a user's group memberships. .. deprecated:: This field is deprecated.""" @@ -87,6 +89,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "DirectoryUserWithGroups": updated_at=_parse_datetime(data["updated_at"]), first_name=data.get("first_name"), last_name=data.get("last_name"), + name=data.get("name"), emails=[ DirectoryUserWithGroupsEmail.from_dict(cast(Dict[str, Any], item)) for item in cast(list[Any], _v_emails) @@ -141,6 +144,10 @@ def to_dict(self) -> Dict[str, Any]: result["last_name"] = self.last_name else: result["last_name"] = None + if self.name is not None: + result["name"] = self.name + else: + result["name"] = None if self.emails is not None: result["emails"] = [item.to_dict() for item in self.emails] if self.job_title is not None: diff --git a/src/workos/events/models/event_schema.py b/src/workos/events/models/event_schema.py index 6dabf048..f508b0ec 100644 --- a/src/workos/events/models/event_schema.py +++ b/src/workos/events/models/event_schema.py @@ -66,6 +66,8 @@ from workos.common.models.dsync_group_updated import DsyncGroupUpdated from workos.common.models.dsync_group_user_added import DsyncGroupUserAdded from workos.common.models.dsync_group_user_removed import DsyncGroupUserRemoved +from workos.common.models.dsync_token_created import DsyncTokenCreated +from workos.common.models.dsync_token_deleted import DsyncTokenDeleted from workos.common.models.dsync_user_created import DsyncUserCreated from workos.common.models.dsync_user_deleted import DsyncUserDeleted from workos.common.models.dsync_user_updated import DsyncUserUpdated @@ -188,6 +190,8 @@ def to_dict(self) -> Dict[str, Any]: DsyncGroupUpdated, DsyncGroupUserAdded, DsyncGroupUserRemoved, + DsyncTokenCreated, + DsyncTokenDeleted, DsyncUserCreated, DsyncUserDeleted, DsyncUserUpdated, @@ -288,6 +292,8 @@ class EventSchema: "dsync.group.updated": DsyncGroupUpdated, "dsync.group.user_added": DsyncGroupUserAdded, "dsync.group.user_removed": DsyncGroupUserRemoved, + "dsync.token.created": DsyncTokenCreated, + "dsync.token.deleted": DsyncTokenDeleted, "dsync.user.created": DsyncUserCreated, "dsync.user.deleted": DsyncUserDeleted, "dsync.user.updated": DsyncUserUpdated, diff --git a/src/workos/groups/_resource.py b/src/workos/groups/_resource.py index c7d4dde5..ba504eb8 100644 --- a/src/workos/groups/_resource.py +++ b/src/workos/groups/_resource.py @@ -8,10 +8,7 @@ from .._client import AsyncWorkOSClient, WorkOSClient from .._types import RequestOptions, enum_value -from .models import Group -from workos.authorization.models.user_organization_membership_base_list_data import ( - UserOrganizationMembershipBaseListData, -) +from .models import Group, UserOrganizationMembershipBaseListData from .models import GroupsOrder from .._pagination import AsyncPage, SyncPage diff --git a/src/workos/groups/models/__init__.py b/src/workos/groups/models/__init__.py index ce775a5e..d0ff45e6 100644 --- a/src/workos/groups/models/__init__.py +++ b/src/workos/groups/models/__init__.py @@ -5,3 +5,6 @@ from .group import Group as Group from .groups_order import GroupsOrder as GroupsOrder from .update_group import UpdateGroup as UpdateGroup +from .user_organization_membership_base_list_data import ( + UserOrganizationMembershipBaseListData as UserOrganizationMembershipBaseListData, +) diff --git a/src/workos/authorization/models/user_organization_membership_base_list_data.py b/src/workos/groups/models/user_organization_membership_base_list_data.py similarity index 100% rename from src/workos/authorization/models/user_organization_membership_base_list_data.py rename to src/workos/groups/models/user_organization_membership_base_list_data.py diff --git a/src/workos/sso/models/profile.py b/src/workos/sso/models/profile.py index b6fb6750..ba036263 100644 --- a/src/workos/sso/models/profile.py +++ b/src/workos/sso/models/profile.py @@ -34,6 +34,8 @@ class Profile: """The user's first name.""" last_name: Optional[str] """The user's last name.""" + name: Optional[str] + """The user's full name.""" raw_attributes: Dict[str, Any] """The complete set of raw attributes returned by the identity provider.""" role: Optional["SlimRole"] = None @@ -59,6 +61,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "Profile": email=data["email"], first_name=data["first_name"], last_name=data["last_name"], + name=data["name"], raw_attributes=data["raw_attributes"], role=SlimRole.from_dict(cast(Dict[str, Any], _v_role)) if (_v_role := data.get("role")) is not None @@ -100,6 +103,10 @@ def to_dict(self) -> Dict[str, Any]: result["last_name"] = self.last_name else: result["last_name"] = None + if self.name is not None: + result["name"] = self.name + else: + result["name"] = None result["raw_attributes"] = self.raw_attributes if self.role is not None: result["role"] = self.role.to_dict() diff --git a/src/workos/user_management/models/organization_membership.py b/src/workos/user_management/models/organization_membership.py index 5375c21a..04b39bf1 100644 --- a/src/workos/user_management/models/organization_membership.py +++ b/src/workos/user_management/models/organization_membership.py @@ -11,6 +11,7 @@ from workos._types import _format_datetime, _parse_datetime from workos.authorization.models.slim_role import SlimRole +from .user import User from workos.common.models.organization_membership_status import ( OrganizationMembershipStatus, ) @@ -38,6 +39,8 @@ class OrganizationMembership: """An ISO 8601 timestamp.""" role: "SlimRole" """The primary role assigned to the user within the organization.""" + user: "User" + """The user that belongs to the organization through this membership.""" organization_name: Optional[str] = None """The name of the organization which the user belongs to.""" custom_attributes: Optional[Dict[str, Any]] = None @@ -57,6 +60,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "OrganizationMembership": created_at=_parse_datetime(data["created_at"]), updated_at=_parse_datetime(data["updated_at"]), role=SlimRole.from_dict(cast(Dict[str, Any], data["role"])), + user=User.from_dict(cast(Dict[str, Any], data["user"])), organization_name=data.get("organization_name"), custom_attributes=data.get("custom_attributes"), ) @@ -77,6 +81,7 @@ def to_dict(self) -> Dict[str, Any]: result["created_at"] = _format_datetime(self.created_at) result["updated_at"] = _format_datetime(self.updated_at) result["role"] = self.role.to_dict() + result["user"] = self.user.to_dict() if self.organization_name is not None: result["organization_name"] = self.organization_name if self.custom_attributes is not None: diff --git a/tests/fixtures/api_key_validation_response_api_key.json b/tests/fixtures/api_key_validation_response_api_key.json new file mode 100644 index 00000000..e05b1db2 --- /dev/null +++ b/tests/fixtures/api_key_validation_response_api_key.json @@ -0,0 +1,17 @@ +{ + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": { + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" + }, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": null, + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/fixtures/api_key_validation_response_api_key_owner.json b/tests/fixtures/api_key_validation_response_api_key_owner.json new file mode 100644 index 00000000..ddbfe81d --- /dev/null +++ b/tests/fixtures/api_key_validation_response_api_key_owner.json @@ -0,0 +1,4 @@ +{ + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/fixtures/directory_user.json b/tests/fixtures/directory_user.json index 68d037ee..67263ead 100644 --- a/tests/fixtures/directory_user.json +++ b/tests/fixtures/directory_user.json @@ -7,6 +7,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/directory_user_with_groups.json b/tests/fixtures/directory_user_with_groups.json index d7d35220..d39d14b9 100644 --- a/tests/fixtures/directory_user_with_groups.json +++ b/tests/fixtures/directory_user_with_groups.json @@ -7,6 +7,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_group_user_added.json b/tests/fixtures/dsync_group_user_added.json index 61c5aac6..50e7ed56 100644 --- a/tests/fixtures/dsync_group_user_added.json +++ b/tests/fixtures/dsync_group_user_added.json @@ -12,6 +12,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_group_user_added_data.json b/tests/fixtures/dsync_group_user_added_data.json index 5ef37883..e0efa882 100644 --- a/tests/fixtures/dsync_group_user_added_data.json +++ b/tests/fixtures/dsync_group_user_added_data.json @@ -9,6 +9,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_group_user_removed.json b/tests/fixtures/dsync_group_user_removed.json index 3b991f47..4f5b9dff 100644 --- a/tests/fixtures/dsync_group_user_removed.json +++ b/tests/fixtures/dsync_group_user_removed.json @@ -12,6 +12,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_group_user_removed_data.json b/tests/fixtures/dsync_group_user_removed_data.json index 5ef37883..e0efa882 100644 --- a/tests/fixtures/dsync_group_user_removed_data.json +++ b/tests/fixtures/dsync_group_user_removed_data.json @@ -9,6 +9,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_token_created.json b/tests/fixtures/dsync_token_created.json new file mode 100644 index 00000000..9cbd9472 --- /dev/null +++ b/tests/fixtures/dsync_token_created.json @@ -0,0 +1,35 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.token.created", + "data": { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": null + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/fixtures/dsync_token_created_data.json b/tests/fixtures/dsync_token_created_data.json new file mode 100644 index 00000000..7dd1d132 --- /dev/null +++ b/tests/fixtures/dsync_token_created_data.json @@ -0,0 +1,9 @@ +{ + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": null +} diff --git a/tests/fixtures/dsync_token_deleted.json b/tests/fixtures/dsync_token_deleted.json new file mode 100644 index 00000000..3b87ac6b --- /dev/null +++ b/tests/fixtures/dsync_token_deleted.json @@ -0,0 +1,35 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.token.deleted", + "data": { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": null + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/fixtures/dsync_token_deleted_data.json b/tests/fixtures/dsync_token_deleted_data.json new file mode 100644 index 00000000..7dd1d132 --- /dev/null +++ b/tests/fixtures/dsync_token_deleted_data.json @@ -0,0 +1,9 @@ +{ + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": null +} diff --git a/tests/fixtures/dsync_user_created.json b/tests/fixtures/dsync_user_created.json index aa1bbc76..87059515 100644 --- a/tests/fixtures/dsync_user_created.json +++ b/tests/fixtures/dsync_user_created.json @@ -10,6 +10,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_user_deleted.json b/tests/fixtures/dsync_user_deleted.json index 26942d25..f18a02dc 100644 --- a/tests/fixtures/dsync_user_deleted.json +++ b/tests/fixtures/dsync_user_deleted.json @@ -10,6 +10,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_user_updated.json b/tests/fixtures/dsync_user_updated.json index 6c0266bf..143dfefb 100644 --- a/tests/fixtures/dsync_user_updated.json +++ b/tests/fixtures/dsync_user_updated.json @@ -10,6 +10,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/dsync_user_updated_data.json b/tests/fixtures/dsync_user_updated_data.json index 0073a535..b8a7ffa6 100644 --- a/tests/fixtures/dsync_user_updated_data.json +++ b/tests/fixtures/dsync_user_updated_data.json @@ -7,6 +7,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/jwt_template_response.json b/tests/fixtures/jwt_template_response.json index b691ce73..00ce7dab 100644 --- a/tests/fixtures/jwt_template_response.json +++ b/tests/fixtures/jwt_template_response.json @@ -1,6 +1,6 @@ { "object": "jwt_template", - "content": "{\"iss\": \"{{environment.id}}\", \"sub\": \"{{user.id}}\"}", + "content": "{\"urn:myapp:full_name\": \"{{user.first_name}} {{user.last_name}}\", \"urn:myapp:email\": \"{{user.email}}\"}", "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z" } diff --git a/tests/fixtures/list_directory_user_with_groups.json b/tests/fixtures/list_directory_user_with_groups.json index 58432bad..dbb44d56 100644 --- a/tests/fixtures/list_directory_user_with_groups.json +++ b/tests/fixtures/list_directory_user_with_groups.json @@ -9,6 +9,7 @@ "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": true, diff --git a/tests/fixtures/list_user_organization_membership.json b/tests/fixtures/list_user_organization_membership.json index cdb823aa..b0764c60 100644 --- a/tests/fixtures/list_user_organization_membership.json +++ b/tests/fixtures/list_user_organization_membership.json @@ -3,7 +3,7 @@ { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "active", "directory_managed": false, @@ -17,6 +17,23 @@ "updated_at": "2026-01-15T12:00:00.000Z", "role": { "slug": "admin" + }, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" } } ], diff --git a/tests/fixtures/list_user_organization_membership_base_list_data.json b/tests/fixtures/list_user_organization_membership_base_list_data.json index b992a1b9..25ff95c0 100644 --- a/tests/fixtures/list_user_organization_membership_base_list_data.json +++ b/tests/fixtures/list_user_organization_membership_base_list_data.json @@ -3,7 +3,7 @@ { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "active", "directory_managed": false, diff --git a/tests/fixtures/list_user_organization_membership_base_with_user.json b/tests/fixtures/list_user_organization_membership_base_with_user.json new file mode 100644 index 00000000..f6dc992a --- /dev/null +++ b/tests/fixtures/list_user_organization_membership_base_with_user.json @@ -0,0 +1,41 @@ +{ + "data": [ + { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/fixtures/organization_membership.json b/tests/fixtures/organization_membership.json index afc05d1e..efba3046 100644 --- a/tests/fixtures/organization_membership.json +++ b/tests/fixtures/organization_membership.json @@ -15,5 +15,22 @@ "updated_at": "2026-01-15T12:00:00.000Z", "role": { "slug": "admin" + }, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" } } diff --git a/tests/fixtures/profile.json b/tests/fixtures/profile.json index 485a13ce..09dcaa63 100644 --- a/tests/fixtures/profile.json +++ b/tests/fixtures/profile.json @@ -8,6 +8,7 @@ "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", + "name": "Todd Rundgren", "role": { "slug": "admin" }, diff --git a/tests/fixtures/sso_token_response.json b/tests/fixtures/sso_token_response.json index 757c3fb1..1f627a4a 100644 --- a/tests/fixtures/sso_token_response.json +++ b/tests/fixtures/sso_token_response.json @@ -12,6 +12,7 @@ "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", + "name": "Todd Rundgren", "role": { "slug": "admin" }, diff --git a/tests/fixtures/update_jwt_template.json b/tests/fixtures/update_jwt_template.json index bb613667..160996e7 100644 --- a/tests/fixtures/update_jwt_template.json +++ b/tests/fixtures/update_jwt_template.json @@ -1,3 +1,3 @@ { - "content": "{\"iss\": \"{{environment.id}}\", \"sub\": \"{{user.id}}\"}" + "content": "{\"urn:myapp:full_name\": \"{{user.first_name}} {{user.last_name}}\", \"urn:myapp:email\": \"{{user.email}}\"}" } diff --git a/tests/fixtures/user_organization_membership.json b/tests/fixtures/user_organization_membership.json index d6acfbe6..184279d9 100644 --- a/tests/fixtures/user_organization_membership.json +++ b/tests/fixtures/user_organization_membership.json @@ -1,7 +1,7 @@ { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "active", "directory_managed": false, @@ -15,5 +15,22 @@ "updated_at": "2026-01-15T12:00:00.000Z", "role": { "slug": "admin" + }, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" } } diff --git a/tests/fixtures/user_organization_membership_base_list_data.json b/tests/fixtures/user_organization_membership_base_list_data.json index a4e9ebde..b42fdcf6 100644 --- a/tests/fixtures/user_organization_membership_base_list_data.json +++ b/tests/fixtures/user_organization_membership_base_list_data.json @@ -1,7 +1,7 @@ { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "active", "directory_managed": false, diff --git a/tests/fixtures/user_organization_membership_base_with_user.json b/tests/fixtures/user_organization_membership_base_with_user.json new file mode 100644 index 00000000..f3a20339 --- /dev/null +++ b/tests/fixtures/user_organization_membership_base_with_user.json @@ -0,0 +1,33 @@ +{ + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/test_authorization.py b/tests/test_authorization.py index c118f925..cc212bc4 100644 --- a/tests/test_authorization.py +++ b/tests/test_authorization.py @@ -14,7 +14,7 @@ Role, RoleAssignment, RoleList, - UserOrganizationMembershipBaseListData, + UserOrganizationMembershipBaseWithUser, AuthorizationAssignment, AuthorizationOrder, PermissionsOrder, @@ -447,7 +447,7 @@ def test_delete_resource_by_external_id_encodes_query_params( def test_list_memberships_for_resource_by_external_id(self, workos, httpx_mock): httpx_mock.add_response( - json=load_fixture("list_user_organization_membership_base_list_data.json"), + json=load_fixture("list_user_organization_membership_base_with_user.json"), ) page = workos.authorization.list_memberships_for_resource_by_external_id( "test_organization_id", @@ -457,7 +457,7 @@ def test_list_memberships_for_resource_by_external_id(self, workos, httpx_mock): ) assert isinstance(page, SyncPage) assert len(page.data) == 1 - assert isinstance(page.data[0], UserOrganizationMembershipBaseListData) + assert isinstance(page.data[0], UserOrganizationMembershipBaseWithUser) def test_list_memberships_for_resource_by_external_id_empty_page( self, workos, httpx_mock @@ -611,14 +611,14 @@ def test_delete_resource_encodes_query_params(self, workos, httpx_mock): def test_list_memberships_for_resource(self, workos, httpx_mock): httpx_mock.add_response( - json=load_fixture("list_user_organization_membership_base_list_data.json"), + json=load_fixture("list_user_organization_membership_base_with_user.json"), ) page = workos.authorization.list_memberships_for_resource( "test_resource_id", permission_slug="test_permission_slug" ) assert isinstance(page, SyncPage) assert len(page.data) == 1 - assert isinstance(page.data[0], UserOrganizationMembershipBaseListData) + assert isinstance(page.data[0], UserOrganizationMembershipBaseWithUser) def test_list_memberships_for_resource_empty_page(self, workos, httpx_mock): httpx_mock.add_response(json={"data": [], "list_metadata": {}}) @@ -1335,7 +1335,7 @@ async def test_list_memberships_for_resource_by_external_id( self, async_workos, httpx_mock ): httpx_mock.add_response( - json=load_fixture("list_user_organization_membership_base_list_data.json") + json=load_fixture("list_user_organization_membership_base_with_user.json") ) page = await async_workos.authorization.list_memberships_for_resource_by_external_id( "test_organization_id", @@ -1345,7 +1345,7 @@ async def test_list_memberships_for_resource_by_external_id( ) assert isinstance(page, AsyncPage) assert len(page.data) == 1 - assert isinstance(page.data[0], UserOrganizationMembershipBaseListData) + assert isinstance(page.data[0], UserOrganizationMembershipBaseWithUser) @pytest.mark.asyncio async def test_list_memberships_for_resource_by_external_id_empty_page( @@ -1499,14 +1499,14 @@ async def test_delete_resource_encodes_query_params(self, async_workos, httpx_mo @pytest.mark.asyncio async def test_list_memberships_for_resource(self, async_workos, httpx_mock): httpx_mock.add_response( - json=load_fixture("list_user_organization_membership_base_list_data.json") + json=load_fixture("list_user_organization_membership_base_with_user.json") ) page = await async_workos.authorization.list_memberships_for_resource( "test_resource_id", permission_slug="test_permission_slug" ) assert isinstance(page, AsyncPage) assert len(page.data) == 1 - assert isinstance(page.data[0], UserOrganizationMembershipBaseListData) + assert isinstance(page.data[0], UserOrganizationMembershipBaseWithUser) @pytest.mark.asyncio async def test_list_memberships_for_resource_empty_page( diff --git a/tests/test_groups.py b/tests/test_groups.py index adcfdae9..3443681e 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -6,8 +6,11 @@ from workos import WorkOSClient, AsyncWorkOSClient from tests.generated_helpers import load_fixture -from workos.authorization.models import UserOrganizationMembershipBaseListData -from workos.groups.models import Group, GroupsOrder +from workos.groups.models import ( + Group, + UserOrganizationMembershipBaseListData, + GroupsOrder, +) from workos._pagination import AsyncPage, SyncPage from workos._errors import ( AuthenticationError, diff --git a/tests/test_models_round_trip.py b/tests/test_models_round_trip.py index 3925830b..2bfb10be 100644 --- a/tests/test_models_round_trip.py +++ b/tests/test_models_round_trip.py @@ -16,6 +16,8 @@ ApiKey, ApiKeyOwner, ApiKeyValidationResponse, + ApiKeyValidationResponseApiKey, + ApiKeyValidationResponseApiKeyOwner, ApiKeyWithValue, ApiKeyWithValueOwner, ) @@ -43,7 +45,7 @@ RoleAssignmentResource, RoleList, SlimRole, - UserOrganizationMembershipBaseListData, + UserOrganizationMembershipBaseWithUser, ) from workos.common.models import ( ActionAuthenticationDenied, @@ -136,6 +138,10 @@ DsyncGroupUserAddedData, DsyncGroupUserRemoved, DsyncGroupUserRemovedData, + DsyncTokenCreated, + DsyncTokenCreatedData, + DsyncTokenDeleted, + DsyncTokenDeletedData, DsyncUserCreated, DsyncUserDeleted, DsyncUserUpdated, @@ -296,7 +302,7 @@ ) from workos.events.models import EventListListMetadata, EventSchema, EventSchemaUnknown from workos.feature_flags.models import FeatureFlag, FeatureFlagOwner, Flag, FlagOwner -from workos.groups.models import Group +from workos.groups.models import Group, UserOrganizationMembershipBaseListData from workos.multi_factor_auth.models import ( AuthenticationChallenge, AuthenticationChallengeVerifyResponse, @@ -710,54 +716,6 @@ def test_external_auth_complete_response_minimal_payload(self): serialized = instance.to_dict() assert serialized["redirect_uri"] == data["redirect_uri"] - def test_api_key_round_trip(self): - data = load_fixture("api_key.json") - instance = ApiKey.from_dict(data) - serialized = instance.to_dict() - assert serialized == data - restored = ApiKey.from_dict(serialized) - assert restored.to_dict() == serialized - - def test_api_key_minimal_payload(self): - data = { - "object": "api_key", - "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", - "owner": {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"}, - "name": "Production API Key", - "obfuscated_value": "sk_...3456", - "last_used_at": None, - "permissions": ["posts:read", "posts:write"], - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = ApiKey.from_dict(data) - serialized = instance.to_dict() - assert serialized["object"] == data["object"] - assert serialized["id"] == data["id"] - assert serialized["owner"] == data["owner"] - assert serialized["name"] == data["name"] - assert serialized["obfuscated_value"] == data["obfuscated_value"] - assert serialized["last_used_at"] == data["last_used_at"] - assert serialized["permissions"] == data["permissions"] - assert serialized["created_at"] == data["created_at"] - assert serialized["updated_at"] == data["updated_at"] - - def test_api_key_preserves_nullable_fields(self): - data = { - "object": "api_key", - "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", - "owner": {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"}, - "name": "Production API Key", - "obfuscated_value": "sk_...3456", - "last_used_at": None, - "permissions": ["posts:read", "posts:write"], - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = ApiKey.from_dict(data) - serialized = instance.to_dict() - assert serialized["last_used_at"] is None - def test_api_key_validation_response_round_trip(self): data = load_fixture("api_key_validation_response.json") instance = ApiKeyValidationResponse.from_dict(data) @@ -1498,6 +1456,202 @@ def test_role_list_minimal_payload(self): assert serialized["object"] == data["object"] assert serialized["data"] == data["data"] + def test_user_round_trip(self): + data = load_fixture("user.json") + instance = User.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = User.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_user_minimal_payload(self): + data = { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": None, + "last_name": None, + "profile_picture_url": None, + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": None, + "last_sign_in_at": None, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = User.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["first_name"] == data["first_name"] + assert serialized["last_name"] == data["last_name"] + assert serialized["profile_picture_url"] == data["profile_picture_url"] + assert serialized["email"] == data["email"] + assert serialized["email_verified"] == data["email_verified"] + assert serialized["external_id"] == data["external_id"] + assert serialized["last_sign_in_at"] == data["last_sign_in_at"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] + + def test_user_omits_absent_optional_non_nullable_fields(self): + data = { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = User.from_dict(data) + serialized = instance.to_dict() + assert "metadata" not in serialized + + def test_user_preserves_nullable_fields(self): + data = { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": None, + "last_name": None, + "profile_picture_url": None, + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": None, + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": None, + "locale": None, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = User.from_dict(data) + serialized = instance.to_dict() + assert serialized["first_name"] is None + assert serialized["last_name"] is None + assert serialized["profile_picture_url"] is None + assert serialized["external_id"] is None + assert serialized["last_sign_in_at"] is None + assert serialized["locale"] is None + + def test_user_organization_membership_base_with_user_round_trip(self): + data = load_fixture("user_organization_membership_base_with_user.json") + instance = UserOrganizationMembershipBaseWithUser.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = UserOrganizationMembershipBaseWithUser.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_user_organization_membership_base_with_user_minimal_payload(self): + data = { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": False, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, + } + instance = UserOrganizationMembershipBaseWithUser.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["user_id"] == data["user_id"] + assert serialized["organization_id"] == data["organization_id"] + assert serialized["status"] == data["status"] + assert serialized["directory_managed"] == data["directory_managed"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] + assert serialized["user"] == data["user"] + + def test_user_organization_membership_base_with_user_omits_absent_optional_non_nullable_fields( + self, + ): + data = { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": False, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, + } + instance = UserOrganizationMembershipBaseWithUser.from_dict(data) + serialized = instance.to_dict() + assert "organization_name" not in serialized + assert "custom_attributes" not in serialized + + def test_user_organization_membership_base_with_user_round_trips_unknown_enum_values( + self, + ): + data = { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "unexpected_user_organization_membership_base_with_user_status", + "directory_managed": False, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn", + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, + } + instance = UserOrganizationMembershipBaseWithUser.from_dict(data) + assert instance.to_dict() == data + def test_connection_round_trip(self): data = load_fixture("connection.json") instance = Connection.from_dict(data) @@ -1780,6 +1934,7 @@ def test_directory_user_with_groups_omits_absent_optional_non_nullable_fields(se "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "job_title": "Software Engineer", "username": "mdavis", "state": "active", @@ -1820,6 +1975,7 @@ def test_directory_user_with_groups_preserves_nullable_fields(self): "email": None, "first_name": None, "last_name": None, + "name": None, "emails": [ { "primary": True, @@ -1858,6 +2014,7 @@ def test_directory_user_with_groups_preserves_nullable_fields(self): assert serialized["email"] is None assert serialized["first_name"] is None assert serialized["last_name"] is None + assert serialized["name"] is None assert serialized["job_title"] is None assert serialized["username"] is None @@ -1871,6 +2028,7 @@ def test_directory_user_with_groups_round_trips_unknown_enum_values(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -2053,6 +2211,7 @@ def test_directory_user_omits_absent_optional_non_nullable_fields(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "job_title": "Software Engineer", "username": "mdavis", "state": "active", @@ -2080,6 +2239,7 @@ def test_directory_user_preserves_nullable_fields(self): "email": None, "first_name": None, "last_name": None, + "name": None, "emails": [ { "primary": True, @@ -2105,6 +2265,7 @@ def test_directory_user_preserves_nullable_fields(self): assert serialized["email"] is None assert serialized["first_name"] is None assert serialized["last_name"] is None + assert serialized["name"] is None assert serialized["job_title"] is None assert serialized["username"] is None @@ -2118,108 +2279,29 @@ def test_directory_user_round_trips_unknown_enum_values(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, - "type": "work", - "value": "marcelina.davis@example.com", - } - ], - "job_title": "Software Engineer", - "username": "mdavis", - "state": "unexpected_directory_user_state", - "raw_attributes": {"key": {}}, - "custom_attributes": { - "department": "Engineering", - "job_title": "Software Engineer", - }, - "role": {"slug": "admin"}, - "roles": [{"slug": "admin"}], - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = DirectoryUser.from_dict(data) - assert instance.to_dict() == data - - def test_user_round_trip(self): - data = load_fixture("user.json") - instance = User.from_dict(data) - serialized = instance.to_dict() - assert serialized == data - restored = User.from_dict(serialized) - assert restored.to_dict() == serialized - - def test_user_minimal_payload(self): - data = { - "object": "user", - "id": "user_01E4ZCR3C56J083X43JQXF3JK5", - "first_name": None, - "last_name": None, - "profile_picture_url": None, - "email": "marcelina.davis@example.com", - "email_verified": True, - "external_id": None, - "last_sign_in_at": None, - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = User.from_dict(data) - serialized = instance.to_dict() - assert serialized["object"] == data["object"] - assert serialized["id"] == data["id"] - assert serialized["first_name"] == data["first_name"] - assert serialized["last_name"] == data["last_name"] - assert serialized["profile_picture_url"] == data["profile_picture_url"] - assert serialized["email"] == data["email"] - assert serialized["email_verified"] == data["email_verified"] - assert serialized["external_id"] == data["external_id"] - assert serialized["last_sign_in_at"] == data["last_sign_in_at"] - assert serialized["created_at"] == data["created_at"] - assert serialized["updated_at"] == data["updated_at"] - - def test_user_omits_absent_optional_non_nullable_fields(self): - data = { - "object": "user", - "id": "user_01E4ZCR3C56J083X43JQXF3JK5", - "first_name": "Marcelina", - "last_name": "Davis", - "profile_picture_url": "https://workoscdn.com/images/v1/123abc", - "email": "marcelina.davis@example.com", - "email_verified": True, - "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", - "last_sign_in_at": "2025-06-25T19:07:33.155Z", - "locale": "en-US", - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = User.from_dict(data) - serialized = instance.to_dict() - assert "metadata" not in serialized - - def test_user_preserves_nullable_fields(self): - data = { - "object": "user", - "id": "user_01E4ZCR3C56J083X43JQXF3JK5", - "first_name": None, - "last_name": None, - "profile_picture_url": None, - "email": "marcelina.davis@example.com", - "email_verified": True, - "external_id": None, - "metadata": {"timezone": "America/New_York"}, - "last_sign_in_at": None, - "locale": None, + "type": "work", + "value": "marcelina.davis@example.com", + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "unexpected_directory_user_state", + "raw_attributes": {"key": {}}, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer", + }, + "role": {"slug": "admin"}, + "roles": [{"slug": "admin"}], "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", } - instance = User.from_dict(data) - serialized = instance.to_dict() - assert serialized["first_name"] is None - assert serialized["last_name"] is None - assert serialized["profile_picture_url"] is None - assert serialized["external_id"] is None - assert serialized["last_sign_in_at"] is None - assert serialized["locale"] is None + instance = DirectoryUser.from_dict(data) + assert instance.to_dict() == data def test_waitlist_user_round_trip(self): data = load_fixture("waitlist_user.json") @@ -6247,6 +6329,216 @@ def test_dsync_group_updated_data_omits_absent_optional_non_nullable_fields(self assert "raw_attributes" not in serialized assert "previous_attributes" not in serialized + def test_dsync_token_created_round_trip(self): + data = load_fixture("dsync_token_created.json") + instance = DsyncTokenCreated.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = DsyncTokenCreated.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_dsync_token_created_minimal_payload(self): + data = { + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.token.created", + "data": { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + }, + "created_at": "2026-01-15T12:00:00.000Z", + "object": "event", + } + instance = DsyncTokenCreated.from_dict(data) + serialized = instance.to_dict() + assert serialized["id"] == data["id"] + assert serialized["event"] == data["event"] + assert serialized["data"] == data["data"] + assert serialized["created_at"] == data["created_at"] + assert serialized["object"] == data["object"] + + def test_dsync_token_created_omits_absent_optional_non_nullable_fields(self): + data = { + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.token.created", + "data": { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + }, + "created_at": "2026-01-15T12:00:00.000Z", + "object": "event", + } + instance = DsyncTokenCreated.from_dict(data) + serialized = instance.to_dict() + assert "context" not in serialized + + def test_dsync_token_created_data_round_trip(self): + data = load_fixture("dsync_token_created_data.json") + instance = DsyncTokenCreatedData.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = DsyncTokenCreatedData.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_dsync_token_created_data_minimal_payload(self): + data = { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + } + instance = DsyncTokenCreatedData.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["directory_id"] == data["directory_id"] + assert serialized["token_suffix"] == data["token_suffix"] + assert serialized["created_at"] == data["created_at"] + assert serialized["expires_at"] == data["expires_at"] + + def test_dsync_token_created_data_omits_absent_optional_non_nullable_fields(self): + data = { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + } + instance = DsyncTokenCreatedData.from_dict(data) + serialized = instance.to_dict() + assert "organization_id" not in serialized + + def test_dsync_token_created_data_preserves_nullable_fields(self): + data = { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + } + instance = DsyncTokenCreatedData.from_dict(data) + serialized = instance.to_dict() + assert serialized["expires_at"] is None + + def test_dsync_token_deleted_round_trip(self): + data = load_fixture("dsync_token_deleted.json") + instance = DsyncTokenDeleted.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = DsyncTokenDeleted.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_dsync_token_deleted_minimal_payload(self): + data = { + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.token.deleted", + "data": { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + }, + "created_at": "2026-01-15T12:00:00.000Z", + "object": "event", + } + instance = DsyncTokenDeleted.from_dict(data) + serialized = instance.to_dict() + assert serialized["id"] == data["id"] + assert serialized["event"] == data["event"] + assert serialized["data"] == data["data"] + assert serialized["created_at"] == data["created_at"] + assert serialized["object"] == data["object"] + + def test_dsync_token_deleted_omits_absent_optional_non_nullable_fields(self): + data = { + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.token.deleted", + "data": { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + }, + "created_at": "2026-01-15T12:00:00.000Z", + "object": "event", + } + instance = DsyncTokenDeleted.from_dict(data) + serialized = instance.to_dict() + assert "context" not in serialized + + def test_dsync_token_deleted_data_round_trip(self): + data = load_fixture("dsync_token_deleted_data.json") + instance = DsyncTokenDeletedData.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = DsyncTokenDeletedData.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_dsync_token_deleted_data_minimal_payload(self): + data = { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + } + instance = DsyncTokenDeletedData.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["directory_id"] == data["directory_id"] + assert serialized["token_suffix"] == data["token_suffix"] + assert serialized["created_at"] == data["created_at"] + assert serialized["expires_at"] == data["expires_at"] + + def test_dsync_token_deleted_data_omits_absent_optional_non_nullable_fields(self): + data = { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + } + instance = DsyncTokenDeletedData.from_dict(data) + serialized = instance.to_dict() + assert "organization_id" not in serialized + + def test_dsync_token_deleted_data_preserves_nullable_fields(self): + data = { + "object": "directory_token", + "id": "directory_token_01EHWNCE74X7JSDV0X3SZ3KJNY", + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "token_suffix": "a1b2", + "created_at": "2026-01-15T12:00:00.000Z", + "expires_at": None, + } + instance = DsyncTokenDeletedData.from_dict(data) + serialized = instance.to_dict() + assert serialized["expires_at"] is None + def test_dsync_group_user_added_round_trip(self): data = load_fixture("dsync_group_user_added.json") instance = DsyncGroupUserAdded.from_dict(data) @@ -6270,6 +6562,7 @@ def test_dsync_group_user_added_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6328,6 +6621,7 @@ def test_dsync_group_user_added_omits_absent_optional_non_nullable_fields(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6387,6 +6681,7 @@ def test_dsync_group_user_added_data_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6446,6 +6741,7 @@ def test_dsync_user_created_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6490,6 +6786,7 @@ def test_dsync_user_created_omits_absent_optional_non_nullable_fields(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6538,6 +6835,7 @@ def test_dsync_user_deleted_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6582,6 +6880,7 @@ def test_dsync_user_deleted_omits_absent_optional_non_nullable_fields(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6632,6 +6931,7 @@ def test_dsync_group_user_removed_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6690,6 +6990,7 @@ def test_dsync_group_user_removed_omits_absent_optional_non_nullable_fields(self "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6749,6 +7050,7 @@ def test_dsync_group_user_removed_data_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6808,6 +7110,7 @@ def test_dsync_user_updated_minimal_payload(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6853,6 +7156,7 @@ def test_dsync_user_updated_omits_absent_optional_non_nullable_fields(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -6930,6 +7234,7 @@ def test_dsync_user_updated_data_omits_absent_optional_non_nullable_fields(self) "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "job_title": "Software Engineer", "username": "mdavis", "state": "active", @@ -6958,6 +7263,7 @@ def test_dsync_user_updated_data_preserves_nullable_fields(self): "email": None, "first_name": None, "last_name": None, + "name": None, "emails": [ { "primary": True, @@ -6984,6 +7290,7 @@ def test_dsync_user_updated_data_preserves_nullable_fields(self): assert serialized["email"] is None assert serialized["first_name"] is None assert serialized["last_name"] is None + assert serialized["name"] is None assert serialized["job_title"] is None assert serialized["username"] is None @@ -6997,6 +7304,7 @@ def test_dsync_user_updated_data_round_trips_unknown_enum_values(self): "email": "marcelina.davis@example.com", "first_name": "Marcelina", "last_name": "Davis", + "name": "Marcelina Davis", "emails": [ { "primary": True, @@ -13618,7 +13926,7 @@ def test_jwt_template_response_round_trip(self): def test_jwt_template_response_minimal_payload(self): data = { "object": "jwt_template", - "content": '{"iss": "{{environment.id}}", "sub": "{{user.id}}"}', + "content": '{"urn:myapp:full_name": "{{user.first_name}} {{user.last_name}}", "urn:myapp:email": "{{user.email}}"}', "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", } @@ -13744,6 +14052,54 @@ def test_flag_preserves_nullable_fields(self): assert serialized["description"] is None assert serialized["owner"] is None + def test_api_key_round_trip(self): + data = load_fixture("api_key.json") + instance = ApiKey.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = ApiKey.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_api_key_minimal_payload(self): + data = { + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"}, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": None, + "permissions": ["posts:read", "posts:write"], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = ApiKey.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["owner"] == data["owner"] + assert serialized["name"] == data["name"] + assert serialized["obfuscated_value"] == data["obfuscated_value"] + assert serialized["last_used_at"] == data["last_used_at"] + assert serialized["permissions"] == data["permissions"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] + + def test_api_key_preserves_nullable_fields(self): + data = { + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"}, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": None, + "permissions": ["posts:read", "posts:write"], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = ApiKey.from_dict(data) + serialized = instance.to_dict() + assert serialized["last_used_at"] is None + def test_api_key_with_value_round_trip(self): data = load_fixture("api_key_with_value.json") instance = ApiKeyWithValue.from_dict(data) @@ -14379,13 +14735,28 @@ def test_user_organization_membership_minimal_payload(self): data = { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "active", "directory_managed": False, "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", "role": {"slug": "admin"}, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, } instance = UserOrganizationMembership.from_dict(data) serialized = instance.to_dict() @@ -14398,6 +14769,7 @@ def test_user_organization_membership_minimal_payload(self): assert serialized["created_at"] == data["created_at"] assert serialized["updated_at"] == data["updated_at"] assert serialized["role"] == data["role"] + assert serialized["user"] == data["user"] def test_user_organization_membership_omits_absent_optional_non_nullable_fields( self, @@ -14405,13 +14777,28 @@ def test_user_organization_membership_omits_absent_optional_non_nullable_fields( data = { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "active", "directory_managed": False, "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", "role": {"slug": "admin"}, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, } instance = UserOrganizationMembership.from_dict(data) serialized = instance.to_dict() @@ -14422,7 +14809,7 @@ def test_user_organization_membership_round_trips_unknown_enum_values(self): data = { "object": "organization_membership", "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", "status": "unexpected_user_organization_membership_status", "directory_managed": False, @@ -14432,9 +14819,24 @@ def test_user_organization_membership_round_trips_unknown_enum_values(self): "title": "Developer Experience Engineer", "location": "Brooklyn", }, - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - "role": {"slug": "admin"}, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "role": {"slug": "admin"}, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, } instance = UserOrganizationMembership.from_dict(data) assert instance.to_dict() == data @@ -14855,6 +15257,7 @@ def test_profile_minimal_payload(self): "email": "todd@example.com", "first_name": None, "last_name": None, + "name": None, "raw_attributes": {"key": {}}, } instance = Profile.from_dict(data) @@ -14868,6 +15271,7 @@ def test_profile_minimal_payload(self): assert serialized["email"] == data["email"] assert serialized["first_name"] == data["first_name"] assert serialized["last_name"] == data["last_name"] + assert serialized["name"] == data["name"] assert serialized["raw_attributes"] == data["raw_attributes"] def test_profile_omits_absent_optional_non_nullable_fields(self): @@ -14881,6 +15285,7 @@ def test_profile_omits_absent_optional_non_nullable_fields(self): "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", + "name": "Todd Rundgren", "role": {"slug": "admin"}, "roles": [{"slug": "admin"}], "raw_attributes": {"key": {}}, @@ -14901,6 +15306,7 @@ def test_profile_preserves_nullable_fields(self): "email": "todd@example.com", "first_name": None, "last_name": None, + "name": None, "role": None, "roles": None, "groups": ["Engineering", "Admins"], @@ -14912,6 +15318,7 @@ def test_profile_preserves_nullable_fields(self): assert serialized["organization_id"] is None assert serialized["first_name"] is None assert serialized["last_name"] is None + assert serialized["name"] is None assert serialized["role"] is None assert serialized["roles"] is None @@ -14926,6 +15333,7 @@ def test_profile_round_trips_unknown_enum_values(self): "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", + "name": "Todd Rundgren", "role": {"slug": "admin"}, "roles": [{"slug": "admin"}], "groups": ["Engineering", "Admins"], @@ -14958,6 +15366,7 @@ def test_sso_token_response_minimal_payload(self): "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", + "name": "Todd Rundgren", "role": {"slug": "admin"}, "roles": [{"slug": "admin"}], "groups": ["Engineering", "Admins"], @@ -14987,6 +15396,7 @@ def test_sso_token_response_omits_absent_optional_non_nullable_fields(self): "email": "todd@example.com", "first_name": "Todd", "last_name": "Rundgren", + "name": "Todd Rundgren", "role": {"slug": "admin"}, "roles": [{"slug": "admin"}], "groups": ["Engineering", "Admins"], @@ -15387,6 +15797,21 @@ def test_api_key_with_value_owner_minimal_payload(self): assert serialized["type"] == data["type"] assert serialized["id"] == data["id"] + def test_api_key_owner_round_trip(self): + data = load_fixture("api_key_owner.json") + instance = ApiKeyOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = ApiKeyOwner.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_api_key_owner_minimal_payload(self): + data = {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"} + instance = ApiKeyOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized["type"] == data["type"] + assert serialized["id"] == data["id"] + def test_flag_owner_round_trip(self): data = load_fixture("flag_owner.json") instance = FlagOwner.from_dict(data) @@ -15479,6 +15904,76 @@ def test_event_context_google_analytics_session_omits_absent_optional_non_nullab assert "sessionId" not in serialized assert "sessionNumber" not in serialized + def test_user_organization_membership_base_list_data_round_trip(self): + data = load_fixture("user_organization_membership_base_list_data.json") + instance = UserOrganizationMembershipBaseListData.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = UserOrganizationMembershipBaseListData.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_user_organization_membership_base_list_data_minimal_payload(self): + data = { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": False, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = UserOrganizationMembershipBaseListData.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["id"] == data["id"] + assert serialized["user_id"] == data["user_id"] + assert serialized["organization_id"] == data["organization_id"] + assert serialized["status"] == data["status"] + assert serialized["directory_managed"] == data["directory_managed"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] + + def test_user_organization_membership_base_list_data_omits_absent_optional_non_nullable_fields( + self, + ): + data = { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": False, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = UserOrganizationMembershipBaseListData.from_dict(data) + serialized = instance.to_dict() + assert "organization_name" not in serialized + assert "custom_attributes" not in serialized + + def test_user_organization_membership_base_list_data_round_trips_unknown_enum_values( + self, + ): + data = { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "unexpected_user_organization_membership_base_list_data_status", + "directory_managed": False, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn", + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = UserOrganizationMembershipBaseListData.from_dict(data) + assert instance.to_dict() == data + def test_directory_user_with_groups_email_round_trip(self): data = load_fixture("directory_user_with_groups_email.json") instance = DirectoryUserWithGroupsEmail.from_dict(data) @@ -15562,76 +16057,6 @@ def test_connection_option_preserves_nullable_fields(self): serialized = instance.to_dict() assert serialized["signing_cert"] is None - def test_user_organization_membership_base_list_data_round_trip(self): - data = load_fixture("user_organization_membership_base_list_data.json") - instance = UserOrganizationMembershipBaseListData.from_dict(data) - serialized = instance.to_dict() - assert serialized == data - restored = UserOrganizationMembershipBaseListData.from_dict(serialized) - assert restored.to_dict() == serialized - - def test_user_organization_membership_base_list_data_minimal_payload(self): - data = { - "object": "organization_membership", - "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", - "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", - "status": "active", - "directory_managed": False, - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = UserOrganizationMembershipBaseListData.from_dict(data) - serialized = instance.to_dict() - assert serialized["object"] == data["object"] - assert serialized["id"] == data["id"] - assert serialized["user_id"] == data["user_id"] - assert serialized["organization_id"] == data["organization_id"] - assert serialized["status"] == data["status"] - assert serialized["directory_managed"] == data["directory_managed"] - assert serialized["created_at"] == data["created_at"] - assert serialized["updated_at"] == data["updated_at"] - - def test_user_organization_membership_base_list_data_omits_absent_optional_non_nullable_fields( - self, - ): - data = { - "object": "organization_membership", - "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", - "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", - "status": "active", - "directory_managed": False, - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = UserOrganizationMembershipBaseListData.from_dict(data) - serialized = instance.to_dict() - assert "organization_name" not in serialized - assert "custom_attributes" not in serialized - - def test_user_organization_membership_base_list_data_round_trips_unknown_enum_values( - self, - ): - data = { - "object": "organization_membership", - "id": "om_01HXYZ123456789ABCDEFGHIJ", - "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", - "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", - "status": "unexpected_user_organization_membership_base_list_data_status", - "directory_managed": False, - "organization_name": "Acme Corp", - "custom_attributes": { - "department": "Engineering", - "title": "Developer Experience Engineer", - "location": "Brooklyn", - }, - "created_at": "2026-01-15T12:00:00.000Z", - "updated_at": "2026-01-15T12:00:00.000Z", - } - instance = UserOrganizationMembershipBaseListData.from_dict(data) - assert instance.to_dict() == data - def test_role_assignment_resource_round_trip(self): data = load_fixture("role_assignment_resource.json") instance = RoleAssignmentResource.from_dict(data) @@ -15812,20 +16237,53 @@ def test_authorized_connect_application_list_data_omits_absent_optional_non_null serialized = instance.to_dict() assert "oauth_resource" not in serialized - def test_api_key_owner_round_trip(self): - data = load_fixture("api_key_owner.json") - instance = ApiKeyOwner.from_dict(data) + def test_api_key_validation_response_api_key_round_trip(self): + data = load_fixture("api_key_validation_response_api_key.json") + instance = ApiKeyValidationResponseApiKey.from_dict(data) serialized = instance.to_dict() assert serialized == data - restored = ApiKeyOwner.from_dict(serialized) + restored = ApiKeyValidationResponseApiKey.from_dict(serialized) assert restored.to_dict() == serialized - def test_api_key_owner_minimal_payload(self): - data = {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"} - instance = ApiKeyOwner.from_dict(data) + def test_api_key_validation_response_api_key_minimal_payload(self): + data = { + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"}, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": None, + "permissions": ["posts:read", "posts:write"], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = ApiKeyValidationResponseApiKey.from_dict(data) serialized = instance.to_dict() - assert serialized["type"] == data["type"] + assert serialized["object"] == data["object"] assert serialized["id"] == data["id"] + assert serialized["owner"] == data["owner"] + assert serialized["name"] == data["name"] + assert serialized["obfuscated_value"] == data["obfuscated_value"] + assert serialized["last_used_at"] == data["last_used_at"] + assert serialized["permissions"] == data["permissions"] + assert serialized["created_at"] == data["created_at"] + assert serialized["updated_at"] == data["updated_at"] + + def test_api_key_validation_response_api_key_preserves_nullable_fields(self): + data = { + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"}, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": None, + "permissions": ["posts:read", "posts:write"], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + } + instance = ApiKeyValidationResponseApiKey.from_dict(data) + serialized = instance.to_dict() + assert serialized["last_used_at"] is None def test_user_consent_option_choice_round_trip(self): data = load_fixture("user_consent_option_choice.json") @@ -16123,6 +16581,21 @@ def test_organization_membership_minimal_payload(self): "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", "role": {"slug": "admin"}, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, } instance = OrganizationMembership.from_dict(data) serialized = instance.to_dict() @@ -16135,6 +16608,7 @@ def test_organization_membership_minimal_payload(self): assert serialized["created_at"] == data["created_at"] assert serialized["updated_at"] == data["updated_at"] assert serialized["role"] == data["role"] + assert serialized["user"] == data["user"] def test_organization_membership_omits_absent_optional_non_nullable_fields(self): data = { @@ -16147,6 +16621,21 @@ def test_organization_membership_omits_absent_optional_non_nullable_fields(self) "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", "role": {"slug": "admin"}, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, } instance = OrganizationMembership.from_dict(data) serialized = instance.to_dict() @@ -16170,6 +16659,21 @@ def test_organization_membership_round_trips_unknown_enum_values(self): "created_at": "2026-01-15T12:00:00.000Z", "updated_at": "2026-01-15T12:00:00.000Z", "role": {"slug": "admin"}, + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": True, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": {"timezone": "America/New_York"}, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + }, } instance = OrganizationMembership.from_dict(data) assert instance.to_dict() == data @@ -16440,6 +16944,21 @@ def test_user_sessions_impersonator_preserves_nullable_fields(self): serialized = instance.to_dict() assert serialized["reason"] is None + def test_api_key_validation_response_api_key_owner_round_trip(self): + data = load_fixture("api_key_validation_response_api_key_owner.json") + instance = ApiKeyValidationResponseApiKeyOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = ApiKeyValidationResponseApiKeyOwner.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_api_key_validation_response_api_key_owner_minimal_payload(self): + data = {"type": "organization", "id": "org_01EHZNVPK3SFK441A1RGBFSHRT"} + instance = ApiKeyValidationResponseApiKeyOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized["type"] == data["type"] + assert serialized["id"] == data["id"] + def test_directory_metadata_user_round_trip(self): data = load_fixture("directory_metadata_user.json") instance = DirectoryMetadataUser.from_dict(data)