diff --git a/okta/models/by_duration_expiry.py b/okta/models/by_duration_expiry.py index b7acd4fc..93a1d6d3 100644 --- a/okta/models/by_duration_expiry.py +++ b/okta/models/by_duration_expiry.py @@ -51,11 +51,11 @@ def value_validate_regular_expression(cls, value): return value if not re.match( - r"^P(?:$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?:\d)(\d+H)?(\d+M)?(\d+S)?)?$", + r"^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$", value, ): raise ValueError( - r"must validate the regular expression /^P(?:$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?:\d)(\d+H)?(\d+M)?(\d+S)?)?$/" + r"must validate the regular expression /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/" ) return value diff --git a/okta/models/grace_period_expiry.py b/okta/models/grace_period_expiry.py index 89b40125..0912bc0d 100644 --- a/okta/models/grace_period_expiry.py +++ b/okta/models/grace_period_expiry.py @@ -130,6 +130,44 @@ def from_json(cls, json_str: str) -> Self: except (ValidationError, ValueError) as e: error_messages.append(str(e)) + # If no match found and the data is a primitive value, retry by wrapping + # it into each oneOf schema's single-property structure. This handles API + # responses where a scalar is returned for a oneOf field whose schemas + # are single-property objects. + if match == 0: + try: + _parsed_value = json.loads(json_str) + except (json.JSONDecodeError, TypeError): + _parsed_value = None + if _parsed_value is not None and isinstance( + _parsed_value, (str, int, float, bool) + ): + _retry_error_messages = [] + # retry ByDateTimeExpiry with wrapped primitive + try: + _model_fields = list(ByDateTimeExpiry.model_fields.keys()) + if len(_model_fields) == 1: + instance.actual_instance = ByDateTimeExpiry.model_validate( + {_model_fields[0]: _parsed_value} + ) + match += 1 + except (ValidationError, ValueError) as e: + _retry_error_messages.append(str(e)) + # retry ByDurationExpiry with wrapped primitive + try: + _model_fields = list(ByDurationExpiry.model_fields.keys()) + if len(_model_fields) == 1: + instance.actual_instance = ByDurationExpiry.model_validate( + {_model_fields[0]: _parsed_value} + ) + match += 1 + except (ValidationError, ValueError) as e: + _retry_error_messages.append(str(e)) + if match > 0: + error_messages = _retry_error_messages + else: + error_messages.extend(_retry_error_messages) + if match > 1: # more than 1 match raise ValueError( diff --git a/openapi/api.yaml b/openapi/api.yaml index f6fd5499..629eb090 100644 --- a/openapi/api.yaml +++ b/openapi/api.yaml @@ -62100,7 +62100,7 @@ components: value: type: string description: A time duration in ISO 8601 duration format. - pattern: ^P(?:$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?:\d)(\d+H)?(\d+M)?(\d+S)?)?$ + pattern: ^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$ CAPTCHAInstance: title: CAPTCHAInstance description: '' @@ -65855,6 +65855,7 @@ components: type: object properties: expiry: + x-okta-primitive-fallback: true oneOf: - $ref: '#/components/schemas/ByDateTimeExpiry' - $ref: '#/components/schemas/ByDurationExpiry' diff --git a/openapi/templates/model_oneof.mustache b/openapi/templates/model_oneof.mustache index 3d281613..6f2152ad 100644 --- a/openapi/templates/model_oneof.mustache +++ b/openapi/templates/model_oneof.mustache @@ -167,6 +167,40 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/isContainer}} {{/composedSchemas.oneOf}} + {{#vendorExtensions.x-okta-primitive-fallback}} + # If no match found and the data is a primitive value, retry by wrapping + # it into each oneOf schema's single-property structure. This handles API + # responses where a scalar is returned for a oneOf field whose schemas + # are single-property objects. + if match == 0: + try: + _parsed_value = json.loads(json_str) + except (json.JSONDecodeError, TypeError): + _parsed_value = None + if _parsed_value is not None and isinstance(_parsed_value, (str, int, float, bool)): + _retry_error_messages = [] + {{#composedSchemas.oneOf}} + {{^isContainer}} + {{^isPrimitiveType}} + {{! Only retry non-primitive, non-container schemas. Primitive oneOf + schemas would have already matched during the initial attempt above. }} + # retry {{{dataType}}} with wrapped primitive + try: + _model_fields = list({{{dataType}}}.model_fields.keys()) + if len(_model_fields) == 1: + instance.actual_instance = {{{dataType}}}.model_validate({_model_fields[0]: _parsed_value}) + match += 1 + except (ValidationError, ValueError) as e: + _retry_error_messages.append(str(e)) + {{/isPrimitiveType}} + {{/isContainer}} + {{/composedSchemas.oneOf}} + if match > 0: + error_messages = _retry_error_messages + else: + error_messages.extend(_retry_error_messages) + {{/vendorExtensions.x-okta-primitive-fallback}} + if match > 1: # more than 1 match raise ValueError("Multiple matches found when deserializing the JSON string into {{{classname}}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Details: " + ", ".join(error_messages))