From 550fb0c04bada6aea56df5211e19dc9395529cfa Mon Sep 17 00:00:00 2001 From: BinoyOza-okta Date: Mon, 24 Aug 2026 00:50:16 +0530 Subject: [PATCH 1/2] fix(spec): resolve UserType name collision with inline User.type schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The top-level UserType component schema (api.yaml) was being generated with only an `id` field, dropping all other properties (name, displayName, description, created, createdBy, default, lastUpdated, lastUpdatedBy, _links). Root cause: OpenAPI Generator 7.x auto-promotes inline object schemas to standalone models, naming them in TitleCase. The `User` schema's inline `type` property (an anonymous object with a single `id` field) was therefore promoted to a model named `UserType`, colliding with the real component of the same name. The inline `{id}`-only shape won, shadowing the full schema. Fix: extract the inline `User.type` object into a new named component `UserTypeRef` and `$ref` it from `User.type`. This frees the `UserType` name for the real component and preserves the on-wire JSON shape (User.type payload is unchanged — still `{ "id": "..." }`). Regenerated SDK reflects the fix: - okta/models/user_type.py now carries the full component schema - okta/models/user_type_ref.py (new) holds the {id}-only shape - okta/models/user.py, user_get_singleton.py: User.type now typed as UserTypeRef instead of UserType - okta/__init__.py, okta/models/__init__.py: export UserTypeRef - docs/UserType.md, docs/UserTypeRef.md, docs/User.md, docs/UserGetSingleton.md updated by generator Added tests/test_user_type.py to guard against regressions of the collision — asserts UserType declares the full component field set, UserTypeRef stays id-only, and covers from_dict/to_dict/JSON roundtrips including the readOnly-field exclusion behavior on serialization. --- docs/User.md | 2 +- docs/UserGetSingleton.md | 2 +- docs/UserType.md | 12 ++- docs/UserTypeRef.md | 30 ++++++ okta/__init__.py | 1 + okta/models/__init__.py | 1 + okta/models/user.py | 6 +- okta/models/user_get_singleton.py | 6 +- okta/models/user_type.py | 97 +++++++++++++++-- okta/models/user_type_ref.py | 92 ++++++++++++++++ openapi/api.yaml | 17 ++- tests/test_user_type.py | 173 ++++++++++++++++++++++++++++++ 12 files changed, 411 insertions(+), 28 deletions(-) create mode 100644 docs/UserTypeRef.md create mode 100644 okta/models/user_type_ref.py create mode 100644 tests/test_user_type.py diff --git a/docs/User.md b/docs/User.md index dd45fca8..7bc563fc 100644 --- a/docs/User.md +++ b/docs/User.md @@ -17,7 +17,7 @@ Name | Type | Description | Notes **status** | [**UserStatus**](UserStatus.md) | | [optional] **status_changed** | **datetime** | The timestamp when the status of the user last changed | [optional] [readonly] **transitioning_to_status** | **str** | The target status of an in-progress asynchronous status transition. This property is only returned if the user's state is transitioning. | [optional] [readonly] -**type** | [**UserType**](UserType.md) | | [optional] +**type** | [**UserTypeRef**](UserTypeRef.md) | | [optional] **embedded** | **Dict[str, object]** | Embedded resources related to the user using the [JSON Hypertext Application Language](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-06) specification | [optional] [readonly] **links** | [**UserLinks**](UserLinks.md) | | [optional] diff --git a/docs/UserGetSingleton.md b/docs/UserGetSingleton.md index 49b227e4..719dd1fe 100644 --- a/docs/UserGetSingleton.md +++ b/docs/UserGetSingleton.md @@ -17,7 +17,7 @@ Name | Type | Description | Notes **status** | [**UserStatus**](UserStatus.md) | | [optional] **status_changed** | **datetime** | The timestamp when the status of the user last changed | [optional] [readonly] **transitioning_to_status** | **str** | The target status of an in-progress asynchronous status transition. This property is only returned if the user's state is transitioning. | [optional] [readonly] -**type** | [**UserType**](UserType.md) | | [optional] +**type** | [**UserTypeRef**](UserTypeRef.md) | | [optional] **embedded** | [**UserGetSingletonAllOfEmbedded**](UserGetSingletonAllOfEmbedded.md) | | [optional] **links** | [**UserLinks**](UserLinks.md) | | [optional] diff --git a/docs/UserType.md b/docs/UserType.md index 11dda203..a5ed9199 100644 --- a/docs/UserType.md +++ b/docs/UserType.md @@ -1,12 +1,20 @@ # UserType -The user type that determines the schema for the user's profile. The `type` property is a map that identifies the [User Types](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/UserType/#tag/UserType). Currently it contains a single element, `id`. It can be specified when creating a new user, and can be updated by an admin on a full replace of an existing user (but not a partial update). ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**id** | **str** | The ID of the user type | [optional] +**created** | **datetime** | A timestamp from when the user type was created | [optional] [readonly] +**created_by** | **str** | The user ID of the account that created the user type | [optional] [readonly] +**default** | **bool** | A boolean value to indicate if this is the default user type | [optional] [readonly] +**description** | **str** | The human-readable description of the user type | [optional] +**display_name** | **str** | The human-readable name of the user type | +**id** | **str** | The unique key for the user type | [optional] [readonly] +**last_updated** | **datetime** | A timestamp from when the user type was most recently updated | [optional] [readonly] +**last_updated_by** | **str** | The user ID of the most recent account to edit the user type | [optional] [readonly] +**name** | **str** | The name of the user type. The name must start with A-Z or a-z and contain only A-Z, a-z, 0-9, or underscore (_) characters. This value becomes read-only after creation and can't be updated. | +**links** | [**UserTypeLinks**](UserTypeLinks.md) | | [optional] ## Example diff --git a/docs/UserTypeRef.md b/docs/UserTypeRef.md new file mode 100644 index 00000000..0c4bd579 --- /dev/null +++ b/docs/UserTypeRef.md @@ -0,0 +1,30 @@ +# UserTypeRef + +The user type that determines the schema for the user's profile... + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**id** | **str** | The ID of the user type | [optional] + +## Example + +```python +from okta.models.user_type_ref import UserTypeRef + +# TODO update the JSON string below +json = "{}" +# create an instance of UserTypeRef from a JSON string +user_type_ref_instance = UserTypeRef.from_json(json) +# print the JSON string representation of the object +print(UserTypeRef.to_json()) + +# convert the object into a dict +user_type_ref_dict = user_type_ref_instance.to_dict() +# create an instance of UserTypeRef from a dict +user_type_ref_from_dict = UserTypeRef.from_dict(user_type_ref_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/okta/__init__.py b/okta/__init__.py index 7540a438..943db5ef 100644 --- a/okta/__init__.py +++ b/okta/__init__.py @@ -1898,6 +1898,7 @@ "UserTypeLinksAllOfSchema": "okta.models.user_type_links_all_of_schema", "UserTypePostRequest": "okta.models.user_type_post_request", "UserTypePutRequest": "okta.models.user_type_put_request", + "UserTypeRef": "okta.models.user_type_ref", "UserVerificationEnum": "okta.models.user_verification_enum", "UsersLink": "okta.models.users_link", "UsersUpdateRequestSchema": "okta.models.users_update_request_schema", diff --git a/okta/models/__init__.py b/okta/models/__init__.py index c40a589d..a8a88077 100644 --- a/okta/models/__init__.py +++ b/okta/models/__init__.py @@ -2100,6 +2100,7 @@ "UserTypeLinksAllOfSchema": "okta.models.user_type_links_all_of_schema", "UserTypePostRequest": "okta.models.user_type_post_request", "UserTypePutRequest": "okta.models.user_type_put_request", + "UserTypeRef": "okta.models.user_type_ref", "UserVerificationEnum": "okta.models.user_verification_enum", "UsersLink": "okta.models.users_link", "UsersUpdateRequestSchema": "okta.models.users_update_request_schema", diff --git a/okta/models/user.py b/okta/models/user.py index 4c7fe250..8dc1d2cf 100644 --- a/okta/models/user.py +++ b/okta/models/user.py @@ -36,7 +36,7 @@ from okta.models.user_links import UserLinks from okta.models.user_profile import UserProfile from okta.models.user_status import UserStatus -from okta.models.user_type import UserType +from okta.models.user_type_ref import UserTypeRef class User(BaseModel): @@ -87,7 +87,7 @@ class User(BaseModel): "the user's state is transitioning.", alias="transitioningToStatus", ) - type: Optional[UserType] = None + type: Optional[UserTypeRef] = None embedded: Optional[Dict[str, Dict[str, Any]]] = Field( default=None, description="Embedded resources related to the user using the [JSON Hypertext Application Language](" @@ -278,7 +278,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "statusChanged": obj.get("statusChanged"), "transitioningToStatus": obj.get("transitioningToStatus"), "type": ( - UserType.from_dict(obj["type"]) + UserTypeRef.from_dict(obj["type"]) if obj.get("type") is not None else None ), diff --git a/okta/models/user_get_singleton.py b/okta/models/user_get_singleton.py index 8cb35ceb..f5442c2e 100644 --- a/okta/models/user_get_singleton.py +++ b/okta/models/user_get_singleton.py @@ -37,7 +37,7 @@ from okta.models.user_links import UserLinks from okta.models.user_profile import UserProfile from okta.models.user_status import UserStatus -from okta.models.user_type import UserType +from okta.models.user_type_ref import UserTypeRef class UserGetSingleton(BaseModel): @@ -88,7 +88,7 @@ class UserGetSingleton(BaseModel): "the user's state is transitioning.", alias="transitioningToStatus", ) - type: Optional[UserType] = None + type: Optional[UserTypeRef] = None embedded: Optional[UserGetSingletonAllOfEmbedded] = Field( default=None, alias="_embedded" ) @@ -281,7 +281,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "statusChanged": obj.get("statusChanged"), "transitioningToStatus": obj.get("transitioningToStatus"), "type": ( - UserType.from_dict(obj["type"]) + UserTypeRef.from_dict(obj["type"]) if obj.get("type") is not None else None ), diff --git a/okta/models/user_type.py b/okta/models/user_type.py index e77f1744..6478bd52 100644 --- a/okta/models/user_type.py +++ b/okta/models/user_type.py @@ -25,23 +25,69 @@ import json import pprint import re # noqa: F401 +from datetime import datetime from typing import Any, ClassVar, Dict, List from typing import Optional, Set -from pydantic import BaseModel, ConfigDict, Field, StrictStr +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing_extensions import Self +from okta.models.user_type_links import UserTypeLinks + class UserType(BaseModel): """ - The user type that determines the schema for the user's profile. The `type` property is a map that identifies the [User - Types](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/UserType/#tag/UserType). Currently it - contains a single element, `id`. It can be specified when creating a new user, and can be updated by an admin on a full - replace of an existing user (but not a partial update). + UserType """ # noqa: E501 - id: Optional[StrictStr] = Field(default=None, description="The ID of the user type") - __properties: ClassVar[List[str]] = ["id"] + created: Optional[datetime] = Field( + default=None, description="A timestamp from when the user type was created" + ) + created_by: Optional[StrictStr] = Field( + default=None, + description="The user ID of the account that created the user type", + alias="createdBy", + ) + default: Optional[StrictBool] = Field( + default=None, + description="A boolean value to indicate if this is the default user type", + ) + description: Optional[StrictStr] = Field( + default=None, description="The human-readable description of the user type" + ) + display_name: StrictStr = Field( + description="The human-readable name of the user type", alias="displayName" + ) + id: Optional[StrictStr] = Field( + default=None, description="The unique key for the user type" + ) + last_updated: Optional[datetime] = Field( + default=None, + description="A timestamp from when the user type was most recently updated", + alias="lastUpdated", + ) + last_updated_by: Optional[StrictStr] = Field( + default=None, + description="The user ID of the most recent account to edit the user type", + alias="lastUpdatedBy", + ) + name: StrictStr = Field( + description="The name of the user type. The name must start with A-Z or a-z and contain only A-Z, a-z, 0-9, " + "or underscore (_) characters. This value becomes read-only after creation and can't be updated." + ) + links: Optional[UserTypeLinks] = Field(default=None, alias="_links") + __properties: ClassVar[List[str]] = [ + "created", + "createdBy", + "default", + "description", + "displayName", + "id", + "lastUpdated", + "lastUpdatedBy", + "name", + "_links", + ] model_config = ConfigDict( populate_by_name=True, @@ -73,13 +119,29 @@ def to_dict(self) -> Dict[str, Any]: were set at model initialization. Other fields with value `None` are ignored. """ - excluded_fields: Set[str] = set([]) + excluded_fields: Set[str] = set( + [ + "created", + "created_by", + "default", + "id", + "last_updated", + "last_updated_by", + ] + ) _dict = self.model_dump( by_alias=True, exclude=excluded_fields, exclude_none=True, ) + # override the default output from pydantic by calling `to_dict()` of links + if self.links: + if not isinstance(self.links, dict): + _dict["_links"] = self.links.to_dict() + else: + _dict["_links"] = self.links + return _dict @classmethod @@ -91,5 +153,22 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: if not isinstance(obj, dict): return cls.model_validate(obj) - _obj = cls.model_validate({"id": obj.get("id")}) + _obj = cls.model_validate( + { + "created": obj.get("created"), + "createdBy": obj.get("createdBy"), + "default": obj.get("default"), + "description": obj.get("description"), + "displayName": obj.get("displayName"), + "id": obj.get("id"), + "lastUpdated": obj.get("lastUpdated"), + "lastUpdatedBy": obj.get("lastUpdatedBy"), + "name": obj.get("name"), + "_links": ( + UserTypeLinks.from_dict(obj["_links"]) + if obj.get("_links") is not None + else None + ), + } + ) return _obj diff --git a/okta/models/user_type_ref.py b/okta/models/user_type_ref.py new file mode 100644 index 00000000..99159c3e --- /dev/null +++ b/okta/models/user_type_ref.py @@ -0,0 +1,92 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS +# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Okta Admin Management + +Allows customers to easily access the Okta Management APIs + +The version of the OpenAPI document: 5.1.0 +Contact: devex-public@okta.com +Generated by OpenAPI Generator (https://openapi-generator.tech) + +Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +import re # noqa: F401 +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class UserTypeRef(BaseModel): + """ + The user type that determines the schema for the user's profile... + """ # noqa: E501 + + id: Optional[StrictStr] = Field(default=None, description="The ID of the user type") + __properties: ClassVar[List[str]] = ["id"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of UserTypeRef from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of UserTypeRef from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({"id": obj.get("id")}) + return _obj diff --git a/openapi/api.yaml b/openapi/api.yaml index 13ff310a..03f2711c 100644 --- a/openapi/api.yaml +++ b/openapi/api.yaml @@ -80711,6 +80711,13 @@ components: id: type: string description: The ID of the user type + UserTypeRef: + type: object + description: The user type that determines the schema for the user's profile... + properties: + id: + type: string + description: The ID of the user type User: type: object properties: @@ -80773,15 +80780,7 @@ components: - DEPROVISIONED - PROVISIONED type: - type: object - description: |- - The user type that determines the schema for the user's profile. The `type` property is a map that identifies the [User Types](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/UserType/#tag/UserType). - - Currently it contains a single element, `id`. It can be specified when creating a new user, and can be updated by an admin on a full replace of an existing user (but not a partial update). - properties: - id: - type: string - description: The ID of the user type + $ref: '#/components/schemas/UserTypeRef' _embedded: type: object description: Embedded resources related to the user using the [JSON Hypertext Application Language](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-06) specification diff --git a/tests/test_user_type.py b/tests/test_user_type.py new file mode 100644 index 00000000..97b59b53 --- /dev/null +++ b/tests/test_user_type.py @@ -0,0 +1,173 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Unit tests for the generated okta.models.user_type.UserType model. + +These tests guard against regressions of the historical name-collision bug where the +inline `User.type` object shadowed the top-level `UserType` component schema, causing +UserType to be generated with only an `id` field. After the api.yaml fix (extracting +the inline schema into `UserTypeRef`), UserType must serialize/deserialize the full +set of fields defined by the component schema. +""" + +from datetime import datetime, timezone + +from okta.models.user_type import UserType + +FULL_PAYLOAD = { + "id": "oty123", + "name": "employee", + "displayName": "Employee", + "description": "Employee user type", + "default": False, + "createdBy": "00ucreated", + "created": "2026-01-02T03:04:05+00:00", + "lastUpdatedBy": "00uupdated", + "lastUpdated": "2026-01-03T04:05:06+00:00", + "_links": {"self": {"href": "https://example.okta.com/api/v1/meta/types/user/oty123"}}, +} + + +class TestUserTypeFromDict: + """Deserialization from wire-format dicts (alias names).""" + + def test_from_dict_preserves_all_response_fields(self): + ut = UserType.from_dict(FULL_PAYLOAD) + + assert ut is not None + assert ut.id == "oty123" + assert ut.name == "employee" + assert ut.display_name == "Employee" + assert ut.description == "Employee user type" + assert ut.default is False + assert ut.created_by == "00ucreated" + assert ut.last_updated_by == "00uupdated" + assert isinstance(ut.created, datetime) + assert isinstance(ut.last_updated, datetime) + assert ut.created == datetime(2026, 1, 2, 3, 4, 5, tzinfo=timezone.utc) + assert ut.last_updated == datetime(2026, 1, 3, 4, 5, 6, tzinfo=timezone.utc) + + def test_from_dict_hydrates_nested_links(self): + ut = UserType.from_dict(FULL_PAYLOAD) + + assert ut.links is not None + # UserTypeLinks stores the `self` alias under attribute `var_self` + assert ut.links.var_self is not None + assert ut.links.var_self.href == "https://example.okta.com/api/v1/meta/types/user/oty123" + + def test_from_dict_returns_none_for_none_input(self): + assert UserType.from_dict(None) is None + + def test_from_dict_ignores_missing_optional_fields(self): + ut = UserType.from_dict({"name": "employee", "displayName": "Employee"}) + + assert ut is not None + assert ut.name == "employee" + assert ut.display_name == "Employee" + assert ut.id is None + assert ut.description is None + assert ut.created is None + assert ut.last_updated is None + assert ut.links is None + + +class TestUserTypeConstruction: + """Model construction rules — required fields, alias support.""" + + def test_requires_name_and_display_name(self): + with pytest.raises(ValidationError) as exc: + UserType(description="missing required fields") + errors = {tuple(e["loc"]) for e in exc.value.errors()} + assert ("name",) in errors + assert ("displayName",) in errors + + def test_accepts_alias_and_field_names(self): + via_alias = UserType(name="employee", displayName="Employee") + via_field = UserType(name="employee", display_name="Employee") + assert via_alias.display_name == via_field.display_name == "Employee" + + +class TestUserTypeToDict: + """Serialization to wire-format dicts. + + The generated to_dict() excludes readOnly fields (created, createdBy, default, + id, lastUpdated, lastUpdatedBy) — see excluded_fields in user_type.py. Only + client-writable fields plus _links are emitted. + """ + + def test_to_dict_excludes_read_only_fields(self): + ut = UserType( + id="oty123", + name="employee", + displayName="Employee", + description="Employee user type", + default=False, + createdBy="00ucreated", + lastUpdatedBy="00uupdated", + ) + + assert ut.to_dict() == { + "name": "employee", + "displayName": "Employee", + "description": "Employee user type", + } + + def test_to_dict_omits_unset_optional_fields(self): + ut = UserType(name="employee", displayName="Employee") + assert ut.to_dict() == {"name": "employee", "displayName": "Employee"} + + def test_to_dict_serializes_links_via_nested_to_dict(self): + ut = UserType.from_dict(FULL_PAYLOAD) + out = ut.to_dict() + assert "_links" in out + assert out["_links"]["self"]["href"] == FULL_PAYLOAD["_links"]["self"]["href"] + + +class TestUserTypeJsonRoundtrip: + def test_from_json_then_to_json_round_trips_writable_fields(self): + import json + + ut = UserType.from_json( + '{"name":"employee","displayName":"Employee","description":"d"}' + ) + assert ut is not None + assert json.loads(ut.to_json()) == { + "name": "employee", + "displayName": "Employee", + "description": "d", + } + + +class TestUserTypeVsUserTypeRef: + """Regression guard for the api.yaml name-collision bug. + + Prior to the spec fix, UserType was generated with only `id` because the inline + `User.type` object shadowed it. That inline shape now lives in UserTypeRef, and + UserType must carry the full component schema. + """ + + def test_user_type_declares_full_component_fields(self): + expected = { + "created", + "created_by", + "default", + "description", + "display_name", + "id", + "last_updated", + "last_updated_by", + "name", + "links", + } + assert expected.issubset(UserType.model_fields.keys()) + + def test_user_type_ref_is_id_only(self): + assert set(UserTypeRef.model_fields.keys()) == {"id"} From eec78979b371f9a6aff9793d7191c1fbcde80ca7 Mon Sep 17 00:00:00 2001 From: BinoyOza-okta Date: Mon, 24 Aug 2026 01:11:02 +0530 Subject: [PATCH 2/2] - Fixed flake8 errors. --- tests/test_user_type.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_user_type.py b/tests/test_user_type.py index 97b59b53..32f248c8 100644 --- a/tests/test_user_type.py +++ b/tests/test_user_type.py @@ -20,7 +20,12 @@ from datetime import datetime, timezone +from pydantic import ValidationError + +import pytest + from okta.models.user_type import UserType +from okta.models.user_type_ref import UserTypeRef FULL_PAYLOAD = { "id": "oty123",