diff --git a/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars b/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars index 3c277d75cb..de39f61701 100644 --- a/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars +++ b/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars @@ -90,48 +90,6 @@ class ApiException(OpenApiException): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -182,3 +140,45 @@ class SchemaValidationError(OpenApiException): num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars b/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars index 687f69905e..dfe8b89e85 100644 --- a/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars +++ b/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars @@ -1870,7 +1870,7 @@ class ComposedBase(Discriminable): continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: {{#if nonCompliantUseDiscriminatorIfCompositionFails}} """ @@ -1929,7 +1929,7 @@ class ComposedBase(Discriminable): try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json b/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json index 0ca68193b5..f35f749a7a 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json +++ b/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json @@ -38,8 +38,6 @@ } ], "description": "This endpoint lets the user run a specified workflow with the provided workflow definition.", - "parameters": [ - ], "requestBody": { "required": true, "content": { diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py index ceecb9ea9f..fae908ded9 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py @@ -29,6 +29,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +54,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py index 15e4771d0d..6c43a25f8c 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py @@ -139,6 +139,8 @@ def __init__(self, host=None, else: raise ClientConfigurationError('API Key "api_key" is required') if x_api_key: + if type(x_api_key) is not str: + raise ClientConfigurationError("x_api_key must be a string") self.api_key['api_key'] = x_api_key elif api_key is None: raise ClientConfigurationError('API Key "api_key" is required') diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py index 9957d85510..ce7650ccc9 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py index 0bfd285585..2bd8c556e2 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py @@ -353,6 +353,7 @@ def workflow( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, @@ -395,6 +396,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi index 58fedb7a0c..faf866638b 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi @@ -344,6 +344,7 @@ class Workflow(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, @@ -386,6 +387,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py index 7c2d1bc339..380c3aabfa 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py @@ -346,6 +346,7 @@ def get_workflow_run( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) @@ -380,6 +381,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi index cfbcc2d7c3..4cb2796a70 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi @@ -337,6 +337,7 @@ class GetWorkflowRun(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) @@ -371,6 +372,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py index cfb09e624e..11a4c80539 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1841,7 +1875,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1876,7 +1910,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1992,6 +2026,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2054,39 +2089,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py index 6a2baa49b4..9906f47082 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py @@ -21,6 +21,7 @@ class RequiredWorkflowRunPostRequest(TypedDict): # The UUID of the workflow to be run. workflow_id: str + class OptionalWorkflowRunPostRequest(TypedDict, total=False): # The URL to which the workflow results should be sent to on completion. webhook_url: str diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py index 316b9ec4ee..4798c4adfb 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_allow_none_for_nullable_ref.pydantic.problematic_schema import ProblematicSchema +from python_allow_none_for_nullable_ref.pydantic.regular_object import RegularObject +from python_allow_none_for_nullable_ref.pydantic.regular_object_nullable import RegularObjectNullable +from python_allow_none_for_nullable_ref.pydantic.request_body import RequestBody + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py index 9711b32cb4..aaa1debf17 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py index 7755ce8cf2..47aa0288b4 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py index d868399094..51af04e95a 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py @@ -327,6 +327,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -391,6 +392,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi index 35d625c23a..8158c9e237 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi @@ -319,6 +319,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -383,6 +384,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py index c2ca176bc0..8739287822 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py index b07989916f..061715e74b 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py index 2d5ad655aa..b2c72ae772 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py index 6bf8bf99b5..375a55c310 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py index f0d569c0eb..af26d78bf1 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py @@ -261,6 +261,7 @@ def fetch( ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -307,6 +308,7 @@ def get( ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi index 1736c4c4f3..6035fdf179 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi @@ -253,6 +253,7 @@ class FetchRaw(BaseApi): ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -299,6 +300,7 @@ class ApiForget(BaseApi): ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py index 6cf0f5293e..1cf975f19a 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py index a10873bf61..84404f50e7 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py index 9fa1f6e420..95321b485a 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py index 1db992503e..afd2a9e3d5 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py index caf87b849e..7c8f07a228 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi index 2740154c21..76f8a31739 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py index 9e4ea0f7af..3bb0ad935e 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py index fdb5ed2204..9f1d593209 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py index 1b0b2e3196..4a4b715ad5 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py index 352c2cd5c0..5e126a4766 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py index bdac0991e8..2e44d5ee70 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi index 3ef0410eca..c275767ba3 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py index 13a8fd2806..b351748bfb 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py index 28c9f5ba1f..6d13df74d0 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py index 906c04a69b..27e08a2f4b 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py index bb50e95580..8b14b63de3 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py index 2824853153..15a089b55c 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi index fa3a5ff74e..f6ce9d8af6 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py index cb7dee4fb9..ae89c9be53 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py index be50c28070..1dcf12b471 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py @@ -24,11 +24,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +55,132 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from carbon.pydantic.add_webhook_props import AddWebhookProps +from carbon.pydantic.body_create_upload_file_uploadfile_post import BodyCreateUploadFileUploadfilePost +from carbon.pydantic.chunk_properties import ChunkProperties +from carbon.pydantic.chunk_properties_nullable import ChunkPropertiesNullable +from carbon.pydantic.chunks_and_embeddings import ChunksAndEmbeddings +from carbon.pydantic.chunks_and_embeddings_embedding import ChunksAndEmbeddingsEmbedding +from carbon.pydantic.chunks_and_embeddings_upload_input import ChunksAndEmbeddingsUploadInput +from carbon.pydantic.configuration_keys import ConfigurationKeys +from carbon.pydantic.data_source_last_sync_actions import DataSourceLastSyncActions +from carbon.pydantic.data_source_sync_statuses import DataSourceSyncStatuses +from carbon.pydantic.data_source_type import DataSourceType +from carbon.pydantic.data_source_type_nullable import DataSourceTypeNullable +from carbon.pydantic.delete_files_query_input import DeleteFilesQueryInput +from carbon.pydantic.delete_files_query_input_file_ids import DeleteFilesQueryInputFileIds +from carbon.pydantic.directory_item import DirectoryItem +from carbon.pydantic.document_response import DocumentResponse +from carbon.pydantic.document_response_list import DocumentResponseList +from carbon.pydantic.document_response_tags import DocumentResponseTags +from carbon.pydantic.document_response_vector import DocumentResponseVector +from carbon.pydantic.embedding_and_chunk import EmbeddingAndChunk +from carbon.pydantic.embedding_and_chunk_embedding import EmbeddingAndChunkEmbedding +from carbon.pydantic.embedding_generators import EmbeddingGenerators +from carbon.pydantic.embedding_generators_nullable import EmbeddingGeneratorsNullable +from carbon.pydantic.embedding_properties import EmbeddingProperties +from carbon.pydantic.embeddings_and_chunks_filters import EmbeddingsAndChunksFilters +from carbon.pydantic.embeddings_and_chunks_order_by_columns import EmbeddingsAndChunksOrderByColumns +from carbon.pydantic.embeddings_and_chunks_query_input import EmbeddingsAndChunksQueryInput +from carbon.pydantic.embeddings_and_chunks_response import EmbeddingsAndChunksResponse +from carbon.pydantic.external_file_sync_statuses import ExternalFileSyncStatuses +from carbon.pydantic.external_source_item import ExternalSourceItem +from carbon.pydantic.fetch_urls_response import FetchURLsResponse +from carbon.pydantic.fetch_urls_response_urls import FetchURLsResponseUrls +from carbon.pydantic.file_content_types import FileContentTypes +from carbon.pydantic.file_content_types_nullable import FileContentTypesNullable +from carbon.pydantic.file_formats import FileFormats +from carbon.pydantic.file_formats_nullable import FileFormatsNullable +from carbon.pydantic.file_statistics import FileStatistics +from carbon.pydantic.file_statistics_nullable import FileStatisticsNullable +from carbon.pydantic.files_query_user_files_deprecated_response import FilesQueryUserFilesDeprecatedResponse +from carbon.pydantic.fresh_desk_connect_request import FreshDeskConnectRequest +from carbon.pydantic.generic_success_response import GenericSuccessResponse +from carbon.pydantic.get_embedding_documents_body import GetEmbeddingDocumentsBody +from carbon.pydantic.get_embedding_documents_body_file_ids import GetEmbeddingDocumentsBodyFileIds +from carbon.pydantic.get_embedding_documents_body_parent_file_ids import GetEmbeddingDocumentsBodyParentFileIds +from carbon.pydantic.get_embedding_documents_body_query_vector import GetEmbeddingDocumentsBodyQueryVector +from carbon.pydantic.get_embedding_documents_body_tags import GetEmbeddingDocumentsBodyTags +from carbon.pydantic.gmail_sync_input import GmailSyncInput +from carbon.pydantic.http_validation_error import HTTPValidationError +from carbon.pydantic.hybrid_search_tuning_params import HybridSearchTuningParams +from carbon.pydantic.hybrid_search_tuning_params_nullable import HybridSearchTuningParamsNullable +from carbon.pydantic.list_data_source_items_request import ListDataSourceItemsRequest +from carbon.pydantic.list_data_source_items_response import ListDataSourceItemsResponse +from carbon.pydantic.list_request import ListRequest +from carbon.pydantic.list_response import ListResponse +from carbon.pydantic.modify_user_configuration_input import ModifyUserConfigurationInput +from carbon.pydantic.o_auth_url_request import OAuthURLRequest +from carbon.pydantic.order_dir import OrderDir +from carbon.pydantic.organization_response import OrganizationResponse +from carbon.pydantic.organization_user_data_source_api import OrganizationUserDataSourceAPI +from carbon.pydantic.organization_user_data_source_filters import OrganizationUserDataSourceFilters +from carbon.pydantic.organization_user_data_source_filters_ids import OrganizationUserDataSourceFiltersIds +from carbon.pydantic.organization_user_data_source_order_by_columns import OrganizationUserDataSourceOrderByColumns +from carbon.pydantic.organization_user_data_source_query_input import OrganizationUserDataSourceQueryInput +from carbon.pydantic.organization_user_data_source_response import OrganizationUserDataSourceResponse +from carbon.pydantic.organization_user_file_tag_create import OrganizationUserFileTagCreate +from carbon.pydantic.organization_user_file_tag_create_tags import OrganizationUserFileTagCreateTags +from carbon.pydantic.organization_user_file_tags_remove import OrganizationUserFileTagsRemove +from carbon.pydantic.organization_user_file_tags_remove_tags import OrganizationUserFileTagsRemoveTags +from carbon.pydantic.organization_user_files_to_sync_filters import OrganizationUserFilesToSyncFilters +from carbon.pydantic.organization_user_files_to_sync_filters_external_file_ids import OrganizationUserFilesToSyncFiltersExternalFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_ids import OrganizationUserFilesToSyncFiltersIds +from carbon.pydantic.organization_user_files_to_sync_filters_organization_user_data_source_id import OrganizationUserFilesToSyncFiltersOrganizationUserDataSourceId +from carbon.pydantic.organization_user_files_to_sync_filters_parent_file_ids import OrganizationUserFilesToSyncFiltersParentFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_tags import OrganizationUserFilesToSyncFiltersTags +from carbon.pydantic.organization_user_files_to_sync_order_by_types import OrganizationUserFilesToSyncOrderByTypes +from carbon.pydantic.organization_user_files_to_sync_query_input import OrganizationUserFilesToSyncQueryInput +from carbon.pydantic.outlook_sync_input import OutlookSyncInput +from carbon.pydantic.pagination import Pagination +from carbon.pydantic.presigned_url_response import PresignedURLResponse +from carbon.pydantic.rss_feed_input import RSSFeedInput +from carbon.pydantic.raw_text_input import RawTextInput +from carbon.pydantic.resync_file_query_input import ResyncFileQueryInput +from carbon.pydantic.revoke_access_token_input import RevokeAccessTokenInput +from carbon.pydantic.s3_auth_request import S3AuthRequest +from carbon.pydantic.s3_file_sync_input import S3FileSyncInput +from carbon.pydantic.s3_get_file_input import S3GetFileInput +from carbon.pydantic.single_chunks_and_embeddings_upload_input import SingleChunksAndEmbeddingsUploadInput +from carbon.pydantic.sitemap_scrape_request import SitemapScrapeRequest +from carbon.pydantic.sitemap_scrape_request_css_classes_to_skip import SitemapScrapeRequestCssClassesToSkip +from carbon.pydantic.sitemap_scrape_request_css_selectors_to_skip import SitemapScrapeRequestCssSelectorsToSkip +from carbon.pydantic.sitemap_scrape_request_html_tags_to_skip import SitemapScrapeRequestHtmlTagsToSkip +from carbon.pydantic.sitemap_scrape_request_tags import SitemapScrapeRequestTags +from carbon.pydantic.sync_directory_request import SyncDirectoryRequest +from carbon.pydantic.sync_files_request import SyncFilesRequest +from carbon.pydantic.sync_files_request_ids import SyncFilesRequestIds +from carbon.pydantic.text_embedding_generators import TextEmbeddingGenerators +from carbon.pydantic.token_response import TokenResponse +from carbon.pydantic.upload_file_from_url_input import UploadFileFromUrlInput +from carbon.pydantic.user_file import UserFile +from carbon.pydantic.user_file_embedding_properties import UserFileEmbeddingProperties +from carbon.pydantic.user_files_v2 import UserFilesV2 +from carbon.pydantic.user_request_content import UserRequestContent +from carbon.pydantic.user_response import UserResponse +from carbon.pydantic.user_response_unique_file_tags import UserResponseUniqueFileTags +from carbon.pydantic.utilities_scrape_web_request import UtilitiesScrapeWebRequest +from carbon.pydantic.validation_error import ValidationError +from carbon.pydantic.validation_error_loc import ValidationErrorLoc +from carbon.pydantic.webhook import Webhook +from carbon.pydantic.webhook_filters import WebhookFilters +from carbon.pydantic.webhook_filters_ids import WebhookFiltersIds +from carbon.pydantic.webhook_no_key import WebhookNoKey +from carbon.pydantic.webhook_order_by_columns import WebhookOrderByColumns +from carbon.pydantic.webhook_query_input import WebhookQueryInput +from carbon.pydantic.webhook_query_response import WebhookQueryResponse +from carbon.pydantic.webscrape_request import WebscrapeRequest +from carbon.pydantic.webscrape_request_css_classes_to_skip import WebscrapeRequestCssClassesToSkip +from carbon.pydantic.webscrape_request_css_selectors_to_skip import WebscrapeRequestCssSelectorsToSkip +from carbon.pydantic.webscrape_request_html_tags_to_skip import WebscrapeRequestHtmlTagsToSkip +from carbon.pydantic.webscrape_request_tags import WebscrapeRequestTags +from carbon.pydantic.white_labeling_response import WhiteLabelingResponse +from carbon.pydantic.youtube_transcript_response import YoutubeTranscriptResponse +from carbon.pydantic.youtube_transcript_response_raw_transcript import YoutubeTranscriptResponseRawTranscript +from carbon.pydantic.youtube_transcript_response_raw_transcript_item import YoutubeTranscriptResponseRawTranscriptItem + @dataclass class MappedArgs: body: typing.Any = None @@ -91,7 +220,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -117,6 +246,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -131,12 +263,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py index e81ca743cb..84710af091 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py @@ -132,10 +132,16 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if access_token: + if type(access_token) is not str: + raise ClientConfigurationError("access_token must be a string") self.api_key['accessToken'] = access_token if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['apiKey'] = api_key if customer_id: + if type(customer_id) is not str: + raise ClientConfigurationError("customer_id must be a string") self.api_key['customerId'] = customer_id """dict to store API key(s) """ diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py index a2106ba541..af955b0550 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py @@ -97,48 +97,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -189,3 +147,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py index c3ba452cb0..45d124edfd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py @@ -351,6 +351,7 @@ def add_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi index 3f66aa7697..2caf7ddfc8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi @@ -342,6 +342,7 @@ class AddUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py index a085fc4c87..86986bf388 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py @@ -294,6 +294,7 @@ def get_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -348,6 +349,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi index 76b358eabd..b4d4d42ae2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi @@ -283,6 +283,7 @@ class GetAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py index 8fc9f8c331..7f4b8433a1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py @@ -292,6 +292,7 @@ def get_white_labeling( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi index b7861ddac6..4916073250 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi @@ -283,6 +283,7 @@ class GetWhiteLabelingRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py index c04675dff0..b3b4a0c738 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py @@ -362,6 +362,7 @@ def create_user_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi index 69a4322a9a..f11dc5a55a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class CreateUserFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py index 235abc7256..a93ce587e9 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py @@ -371,6 +371,7 @@ def delete_many( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi index 182f67b86d..a0d4cb6bfd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi @@ -360,6 +360,7 @@ class DeleteManyRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py index edce34b474..0cde98e54b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py @@ -362,6 +362,7 @@ def delete_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi index 346b07e758..ed024015ca 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class DeleteFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py index e9557430ba..0e57727add 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py @@ -357,6 +357,7 @@ def delete_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -421,6 +422,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi index fdca5fbb52..bf0ec9856a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py index 7910ff35fa..47ef692d57 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py @@ -359,6 +359,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -423,6 +424,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi index 26697b2ed1..194d823245 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py index cda04a5023..a98428a48d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py @@ -452,6 +452,7 @@ def get_documents( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -620,6 +621,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi index 82f31cf3ed..f5c39b652d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi @@ -441,6 +441,7 @@ class GetDocumentsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -609,6 +610,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py index fa43720b0b..1857466136 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py @@ -362,6 +362,7 @@ def fetch_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi index c16ed4320a..7da5391d1a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi @@ -351,6 +351,7 @@ class FetchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py index e1f1aeedc4..9102ce93a0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py @@ -378,6 +378,7 @@ def fetch_youtube_transcripts( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -450,6 +451,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi index 4dc01c1bd5..1210d71a69 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi @@ -367,6 +367,7 @@ class FetchYoutubeTranscriptsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -439,6 +440,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py index 6188e3d6d3..68be5b43a5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py @@ -257,6 +257,7 @@ def check( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -311,6 +312,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi index b93a5cef84..c37513c8c8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi @@ -252,6 +252,7 @@ class CheckRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -306,6 +307,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py index ce14dd256d..15556cccc2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py @@ -359,6 +359,7 @@ def list_confluence_pages( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi index dceff6d8c0..96a5fe2cc5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi @@ -348,6 +348,7 @@ class ListConfluencePagesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py index f066d09a71..2cc9d4037d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py @@ -413,6 +413,7 @@ def sync_confluence( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi index dae7c5783b..4e8f234c75 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi @@ -402,6 +402,7 @@ class SyncConfluenceRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py index 03315198af..1d254ec9f4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py @@ -413,6 +413,7 @@ def sync_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi index 0218b421a4..5ac5a8d90a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi @@ -402,6 +402,7 @@ class SyncFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py index e95129f3e5..438d321a78 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py @@ -404,6 +404,7 @@ def connect_freshdesk( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi index fc60b74309..c4131669a5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi @@ -393,6 +393,7 @@ class ConnectFreshdeskRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py index 5f29f72f13..462fee83a2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py @@ -398,6 +398,7 @@ def sync_gmail( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi index bd24219b05..a5c539360b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi @@ -387,6 +387,7 @@ class SyncGmailRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py index 1553396f34..82b93e8c68 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py @@ -291,6 +291,7 @@ def list_labels( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi index 574e8e2f2d..d4808e001e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi @@ -280,6 +280,7 @@ class ListLabelsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py index 7b86208e5c..06d19008b4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py @@ -368,6 +368,7 @@ def list_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -448,6 +449,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi index 9ada873e5f..b527a3dca5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi @@ -357,6 +357,7 @@ class ListDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -437,6 +438,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py index 3bc22043da..6c241127f5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py @@ -353,6 +353,7 @@ def sync_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi index 693fc6b901..777130cedd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi @@ -342,6 +342,7 @@ class SyncDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py index cf0aadb9d9..12974467a0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py @@ -434,6 +434,7 @@ def get_oauth_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -602,6 +603,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi index 02a57a8775..862acff67f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi @@ -423,6 +423,7 @@ class GetOauthUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -591,6 +592,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py index 2ff3a0409d..ee5ba6e5cd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py @@ -404,6 +404,7 @@ def sync_outlook( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi index 9e1aec668a..044800b7d1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi @@ -393,6 +393,7 @@ class SyncOutlookRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py index 32f95f5d62..8875324408 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py @@ -291,6 +291,7 @@ def list_folders( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi index a2561e2a7a..865805aebc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi @@ -280,6 +280,7 @@ class ListFoldersRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py index 06b5fcd608..4e77986453 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py @@ -398,6 +398,7 @@ def sync_rss_feed( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi index b4f2224772..b09e42354b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi @@ -387,6 +387,7 @@ class SyncRssFeedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py index 4bf037d808..fb7f392aa3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py @@ -359,6 +359,7 @@ def create_aws_iam_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi index 4c723594f6..79afa2f0e9 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi @@ -348,6 +348,7 @@ class CreateAwsIamUserRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py index 00593c1e88..843e0fcc8a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py @@ -407,6 +407,7 @@ def sync_s3_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -535,6 +536,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi index 60e001e856..801e982974 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi @@ -396,6 +396,7 @@ class SyncS3FilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -524,6 +525,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py index 29a5e6ba97..88bc495ce7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py @@ -359,6 +359,7 @@ def toggle_user_features( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi index c30af2aeac..535f161d6f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi @@ -348,6 +348,7 @@ class ToggleUserFeaturesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py index 1be29c59e4..83f948d7b1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py @@ -292,6 +292,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi index cced7688ad..533208c04f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi @@ -283,6 +283,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py index af4a2e48a7..231012a2b8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py @@ -361,6 +361,7 @@ def get_parsed_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi index 0adabb1350..fad322dbc4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetParsedFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py index 75a641e301..74a7dcf779 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py @@ -359,6 +359,7 @@ def process_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -423,6 +424,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi index 4abb267c7d..1276ced736 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi @@ -348,6 +348,7 @@ class ProcessSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -412,6 +413,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py index a4a0e471bb..1d482b74f6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py @@ -361,6 +361,7 @@ def get_raw_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi index 46a8c43930..bbe9767c4b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetRawFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py index 01d7c4d352..77e4461026 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py @@ -365,6 +365,7 @@ def resync( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -445,6 +446,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi index b1036d310b..671a0913ef 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi @@ -354,6 +354,7 @@ class ResyncRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -434,6 +435,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py index 9fbca0ffaa..200e42e230 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py @@ -353,6 +353,7 @@ def revoke_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi index 17045520f0..a547134ef6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi @@ -342,6 +342,7 @@ class RevokeAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py index 51f2a96cd3..b0446441f8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py @@ -428,6 +428,7 @@ def scrape_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -580,6 +581,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi index 6804689067..51312f0e35 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi @@ -417,6 +417,7 @@ class ScrapeSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -569,6 +570,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py index 9cae2e6dcd..9be54dad09 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py @@ -362,6 +362,7 @@ def search_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi index a5d7bdded3..17d04d9493 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi @@ -351,6 +351,7 @@ class SearchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py index d3ba1bd9e1..981c03b61c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py @@ -389,6 +389,7 @@ def get_embeddings_and_chunks( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -485,6 +486,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi index cc02415d19..392b6143d5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi @@ -378,6 +378,7 @@ class GetEmbeddingsAndChunksRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -474,6 +475,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py index c925481db1..e489185e01 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py @@ -371,6 +371,7 @@ def upload_chunks_and_embeddings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi index f2a96c6946..6ca4f9916a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi @@ -360,6 +360,7 @@ class UploadChunksAndEmbeddingsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py index d33b565e42..b176fc3601 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py @@ -416,6 +416,7 @@ def upload_from_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -560,6 +561,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi index 63447dcae7..2362aedc72 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi @@ -405,6 +405,7 @@ class UploadFromUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -549,6 +550,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py index 2579dc20b2..330f1d4361 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py @@ -398,6 +398,7 @@ def upload_text( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi index 3df5f38644..59569ee31a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi @@ -387,6 +387,7 @@ class UploadTextRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py index 8dd18d5a26..fc668dfd15 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py @@ -608,6 +608,7 @@ def upload( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -746,6 +747,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi index ee1e8b24fa..0319520a3c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi @@ -597,6 +597,7 @@ class UploadRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -735,6 +736,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py index e2c6918e57..e0ee2e3d3c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py @@ -351,6 +351,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi index 681cb4c1bb..c72d7177e2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi @@ -342,6 +342,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py index a351b150f2..f0f9900e00 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py @@ -383,6 +383,7 @@ def query_user_data_sources( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -471,6 +472,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi index f83936aa72..c47c170d35 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi @@ -372,6 +372,7 @@ class QueryUserDataSourcesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py index eee7b8f4ee..8386563979 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py @@ -403,6 +403,7 @@ def query_user_files_deprecated( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -519,6 +520,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi index aa114dd86c..1c25b968a7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi @@ -392,6 +392,7 @@ class QueryUserFilesDeprecatedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -508,6 +509,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py index 79f7bce933..95f7462ae7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py @@ -401,6 +401,7 @@ def query_user_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -513,6 +514,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi index 2fe4823b6c..9a14d2b8a6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi @@ -390,6 +390,7 @@ class QueryUserFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -502,6 +503,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py index 2188240631..c240d52c83 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py @@ -348,6 +348,7 @@ def scrape_web( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -412,6 +413,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi index 0c3a3687a0..f66f992a75 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi @@ -337,6 +337,7 @@ class ScrapeWebRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -401,6 +402,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py index 3f2273b517..fc2016aa79 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py @@ -381,6 +381,7 @@ def urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -469,6 +470,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi index 93428441ae..a39501dd99 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi @@ -372,6 +372,7 @@ class UrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py index c1eb1c998c..a2f3497071 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1843,7 +1877,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1878,7 +1912,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1994,6 +2028,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2056,39 +2091,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py index 54b9dba341..b0f05eac52 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py @@ -22,6 +22,7 @@ class RequiredChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[SingleChunksAndEmbeddingsUploadInput] + class OptionalChunksAndEmbeddingsUploadInput(TypedDict, total=False): overwrite_existing: bool diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py index 2d09407e3c..2f790977d4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py @@ -19,6 +19,7 @@ class RequiredEmbeddingsAndChunksFilters(TypedDict): user_file_id: int + class OptionalEmbeddingsAndChunksFilters(TypedDict, total=False): embedding_model: typing.Optional[EmbeddingGeneratorsNullable] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py index 196596694b..b7837260ef 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py @@ -22,6 +22,7 @@ class RequiredEmbeddingsAndChunksQueryInput(TypedDict): filters: EmbeddingsAndChunksFilters + class OptionalEmbeddingsAndChunksQueryInput(TypedDict, total=False): pagination: Pagination diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py index 3ebb97608a..397a2bd7d6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py @@ -21,6 +21,7 @@ class RequiredFreshDeskConnectRequest(TypedDict): api_key: str + class OptionalFreshDeskConnectRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py index da727a2b5b..9286d1487c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py @@ -29,6 +29,7 @@ class RequiredGetEmbeddingDocumentsBody(TypedDict): # Number of related chunks to return. k: int + class OptionalGetEmbeddingDocumentsBody(TypedDict, total=False): tags: typing.Optional[GetEmbeddingDocumentsBodyTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py index 5d1d23c66c..44979438b5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py @@ -19,6 +19,7 @@ class RequiredGmailSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalGmailSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py index 8dc016b743..7598773465 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py @@ -19,6 +19,7 @@ class RequiredListDataSourceItemsRequest(TypedDict): data_source_id: int + class OptionalListDataSourceItemsRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py index 8715645d67..7eeff13db2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py @@ -18,6 +18,7 @@ class RequiredListRequest(TypedDict): data_source_id: int + class OptionalListRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py index 82b13ced32..9aacadf64a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py @@ -20,6 +20,7 @@ class RequiredOAuthURLRequest(TypedDict): service: DataSourceType + class OptionalOAuthURLRequest(TypedDict, total=False): tags: typing.Union[bool, date, datetime, dict, float, int, list, str, None] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py index f9c3ce6c0a..9c498c370c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py @@ -19,6 +19,7 @@ class RequiredOutlookSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalOutlookSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py index 477993e3c0..208765ba7c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py @@ -19,6 +19,7 @@ class RequiredRawTextInput(TypedDict): contents: str + class OptionalRawTextInput(TypedDict, total=False): name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py index f6cec1e81d..d343c6672f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py @@ -18,6 +18,7 @@ class RequiredResyncFileQueryInput(TypedDict): file_id: int + class OptionalResyncFileQueryInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py index 6f4459e1d3..b82314f9d7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py @@ -19,6 +19,7 @@ class RequiredRSSFeedInput(TypedDict): url: str + class OptionalRSSFeedInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py index 309f5e04d6..326e013fcb 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py @@ -20,6 +20,7 @@ class RequiredS3FileSyncInput(TypedDict): ids: typing.List[S3GetFileInput] + class OptionalS3FileSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py index b9b527ca92..20388cc53b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py @@ -21,6 +21,7 @@ class RequiredSingleChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[ChunksAndEmbeddings] + class OptionalSingleChunksAndEmbeddingsUploadInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py index c04ad96066..0410ccb058 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py @@ -22,6 +22,7 @@ class RequiredSitemapScrapeRequest(TypedDict): url: str + class OptionalSitemapScrapeRequest(TypedDict, total=False): tags: typing.Optional[SitemapScrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py index a79a55db68..42565acca0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py @@ -22,6 +22,7 @@ class RequiredSyncFilesRequest(TypedDict): ids: SyncFilesRequestIds + class OptionalSyncFilesRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py index e3b523aa4d..a247797ba1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py @@ -19,6 +19,7 @@ class RequiredUploadFileFromUrlInput(TypedDict): url: str + class OptionalUploadFileFromUrlInput(TypedDict, total=False): file_name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py index 794562fec2..bfc385925d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py @@ -22,6 +22,7 @@ class RequiredWebscrapeRequest(TypedDict): url: str + class OptionalWebscrapeRequest(TypedDict, total=False): tags: typing.Optional[WebscrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py index be50c28070..1dcf12b471 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py @@ -24,11 +24,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +55,132 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from carbon.pydantic.add_webhook_props import AddWebhookProps +from carbon.pydantic.body_create_upload_file_uploadfile_post import BodyCreateUploadFileUploadfilePost +from carbon.pydantic.chunk_properties import ChunkProperties +from carbon.pydantic.chunk_properties_nullable import ChunkPropertiesNullable +from carbon.pydantic.chunks_and_embeddings import ChunksAndEmbeddings +from carbon.pydantic.chunks_and_embeddings_embedding import ChunksAndEmbeddingsEmbedding +from carbon.pydantic.chunks_and_embeddings_upload_input import ChunksAndEmbeddingsUploadInput +from carbon.pydantic.configuration_keys import ConfigurationKeys +from carbon.pydantic.data_source_last_sync_actions import DataSourceLastSyncActions +from carbon.pydantic.data_source_sync_statuses import DataSourceSyncStatuses +from carbon.pydantic.data_source_type import DataSourceType +from carbon.pydantic.data_source_type_nullable import DataSourceTypeNullable +from carbon.pydantic.delete_files_query_input import DeleteFilesQueryInput +from carbon.pydantic.delete_files_query_input_file_ids import DeleteFilesQueryInputFileIds +from carbon.pydantic.directory_item import DirectoryItem +from carbon.pydantic.document_response import DocumentResponse +from carbon.pydantic.document_response_list import DocumentResponseList +from carbon.pydantic.document_response_tags import DocumentResponseTags +from carbon.pydantic.document_response_vector import DocumentResponseVector +from carbon.pydantic.embedding_and_chunk import EmbeddingAndChunk +from carbon.pydantic.embedding_and_chunk_embedding import EmbeddingAndChunkEmbedding +from carbon.pydantic.embedding_generators import EmbeddingGenerators +from carbon.pydantic.embedding_generators_nullable import EmbeddingGeneratorsNullable +from carbon.pydantic.embedding_properties import EmbeddingProperties +from carbon.pydantic.embeddings_and_chunks_filters import EmbeddingsAndChunksFilters +from carbon.pydantic.embeddings_and_chunks_order_by_columns import EmbeddingsAndChunksOrderByColumns +from carbon.pydantic.embeddings_and_chunks_query_input import EmbeddingsAndChunksQueryInput +from carbon.pydantic.embeddings_and_chunks_response import EmbeddingsAndChunksResponse +from carbon.pydantic.external_file_sync_statuses import ExternalFileSyncStatuses +from carbon.pydantic.external_source_item import ExternalSourceItem +from carbon.pydantic.fetch_urls_response import FetchURLsResponse +from carbon.pydantic.fetch_urls_response_urls import FetchURLsResponseUrls +from carbon.pydantic.file_content_types import FileContentTypes +from carbon.pydantic.file_content_types_nullable import FileContentTypesNullable +from carbon.pydantic.file_formats import FileFormats +from carbon.pydantic.file_formats_nullable import FileFormatsNullable +from carbon.pydantic.file_statistics import FileStatistics +from carbon.pydantic.file_statistics_nullable import FileStatisticsNullable +from carbon.pydantic.files_query_user_files_deprecated_response import FilesQueryUserFilesDeprecatedResponse +from carbon.pydantic.fresh_desk_connect_request import FreshDeskConnectRequest +from carbon.pydantic.generic_success_response import GenericSuccessResponse +from carbon.pydantic.get_embedding_documents_body import GetEmbeddingDocumentsBody +from carbon.pydantic.get_embedding_documents_body_file_ids import GetEmbeddingDocumentsBodyFileIds +from carbon.pydantic.get_embedding_documents_body_parent_file_ids import GetEmbeddingDocumentsBodyParentFileIds +from carbon.pydantic.get_embedding_documents_body_query_vector import GetEmbeddingDocumentsBodyQueryVector +from carbon.pydantic.get_embedding_documents_body_tags import GetEmbeddingDocumentsBodyTags +from carbon.pydantic.gmail_sync_input import GmailSyncInput +from carbon.pydantic.http_validation_error import HTTPValidationError +from carbon.pydantic.hybrid_search_tuning_params import HybridSearchTuningParams +from carbon.pydantic.hybrid_search_tuning_params_nullable import HybridSearchTuningParamsNullable +from carbon.pydantic.list_data_source_items_request import ListDataSourceItemsRequest +from carbon.pydantic.list_data_source_items_response import ListDataSourceItemsResponse +from carbon.pydantic.list_request import ListRequest +from carbon.pydantic.list_response import ListResponse +from carbon.pydantic.modify_user_configuration_input import ModifyUserConfigurationInput +from carbon.pydantic.o_auth_url_request import OAuthURLRequest +from carbon.pydantic.order_dir import OrderDir +from carbon.pydantic.organization_response import OrganizationResponse +from carbon.pydantic.organization_user_data_source_api import OrganizationUserDataSourceAPI +from carbon.pydantic.organization_user_data_source_filters import OrganizationUserDataSourceFilters +from carbon.pydantic.organization_user_data_source_filters_ids import OrganizationUserDataSourceFiltersIds +from carbon.pydantic.organization_user_data_source_order_by_columns import OrganizationUserDataSourceOrderByColumns +from carbon.pydantic.organization_user_data_source_query_input import OrganizationUserDataSourceQueryInput +from carbon.pydantic.organization_user_data_source_response import OrganizationUserDataSourceResponse +from carbon.pydantic.organization_user_file_tag_create import OrganizationUserFileTagCreate +from carbon.pydantic.organization_user_file_tag_create_tags import OrganizationUserFileTagCreateTags +from carbon.pydantic.organization_user_file_tags_remove import OrganizationUserFileTagsRemove +from carbon.pydantic.organization_user_file_tags_remove_tags import OrganizationUserFileTagsRemoveTags +from carbon.pydantic.organization_user_files_to_sync_filters import OrganizationUserFilesToSyncFilters +from carbon.pydantic.organization_user_files_to_sync_filters_external_file_ids import OrganizationUserFilesToSyncFiltersExternalFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_ids import OrganizationUserFilesToSyncFiltersIds +from carbon.pydantic.organization_user_files_to_sync_filters_organization_user_data_source_id import OrganizationUserFilesToSyncFiltersOrganizationUserDataSourceId +from carbon.pydantic.organization_user_files_to_sync_filters_parent_file_ids import OrganizationUserFilesToSyncFiltersParentFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_tags import OrganizationUserFilesToSyncFiltersTags +from carbon.pydantic.organization_user_files_to_sync_order_by_types import OrganizationUserFilesToSyncOrderByTypes +from carbon.pydantic.organization_user_files_to_sync_query_input import OrganizationUserFilesToSyncQueryInput +from carbon.pydantic.outlook_sync_input import OutlookSyncInput +from carbon.pydantic.pagination import Pagination +from carbon.pydantic.presigned_url_response import PresignedURLResponse +from carbon.pydantic.rss_feed_input import RSSFeedInput +from carbon.pydantic.raw_text_input import RawTextInput +from carbon.pydantic.resync_file_query_input import ResyncFileQueryInput +from carbon.pydantic.revoke_access_token_input import RevokeAccessTokenInput +from carbon.pydantic.s3_auth_request import S3AuthRequest +from carbon.pydantic.s3_file_sync_input import S3FileSyncInput +from carbon.pydantic.s3_get_file_input import S3GetFileInput +from carbon.pydantic.single_chunks_and_embeddings_upload_input import SingleChunksAndEmbeddingsUploadInput +from carbon.pydantic.sitemap_scrape_request import SitemapScrapeRequest +from carbon.pydantic.sitemap_scrape_request_css_classes_to_skip import SitemapScrapeRequestCssClassesToSkip +from carbon.pydantic.sitemap_scrape_request_css_selectors_to_skip import SitemapScrapeRequestCssSelectorsToSkip +from carbon.pydantic.sitemap_scrape_request_html_tags_to_skip import SitemapScrapeRequestHtmlTagsToSkip +from carbon.pydantic.sitemap_scrape_request_tags import SitemapScrapeRequestTags +from carbon.pydantic.sync_directory_request import SyncDirectoryRequest +from carbon.pydantic.sync_files_request import SyncFilesRequest +from carbon.pydantic.sync_files_request_ids import SyncFilesRequestIds +from carbon.pydantic.text_embedding_generators import TextEmbeddingGenerators +from carbon.pydantic.token_response import TokenResponse +from carbon.pydantic.upload_file_from_url_input import UploadFileFromUrlInput +from carbon.pydantic.user_file import UserFile +from carbon.pydantic.user_file_embedding_properties import UserFileEmbeddingProperties +from carbon.pydantic.user_files_v2 import UserFilesV2 +from carbon.pydantic.user_request_content import UserRequestContent +from carbon.pydantic.user_response import UserResponse +from carbon.pydantic.user_response_unique_file_tags import UserResponseUniqueFileTags +from carbon.pydantic.utilities_scrape_web_request import UtilitiesScrapeWebRequest +from carbon.pydantic.validation_error import ValidationError +from carbon.pydantic.validation_error_loc import ValidationErrorLoc +from carbon.pydantic.webhook import Webhook +from carbon.pydantic.webhook_filters import WebhookFilters +from carbon.pydantic.webhook_filters_ids import WebhookFiltersIds +from carbon.pydantic.webhook_no_key import WebhookNoKey +from carbon.pydantic.webhook_order_by_columns import WebhookOrderByColumns +from carbon.pydantic.webhook_query_input import WebhookQueryInput +from carbon.pydantic.webhook_query_response import WebhookQueryResponse +from carbon.pydantic.webscrape_request import WebscrapeRequest +from carbon.pydantic.webscrape_request_css_classes_to_skip import WebscrapeRequestCssClassesToSkip +from carbon.pydantic.webscrape_request_css_selectors_to_skip import WebscrapeRequestCssSelectorsToSkip +from carbon.pydantic.webscrape_request_html_tags_to_skip import WebscrapeRequestHtmlTagsToSkip +from carbon.pydantic.webscrape_request_tags import WebscrapeRequestTags +from carbon.pydantic.white_labeling_response import WhiteLabelingResponse +from carbon.pydantic.youtube_transcript_response import YoutubeTranscriptResponse +from carbon.pydantic.youtube_transcript_response_raw_transcript import YoutubeTranscriptResponseRawTranscript +from carbon.pydantic.youtube_transcript_response_raw_transcript_item import YoutubeTranscriptResponseRawTranscriptItem + @dataclass class MappedArgs: body: typing.Any = None @@ -91,7 +220,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -117,6 +246,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -131,12 +263,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py index e81ca743cb..84710af091 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py @@ -132,10 +132,16 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if access_token: + if type(access_token) is not str: + raise ClientConfigurationError("access_token must be a string") self.api_key['accessToken'] = access_token if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['apiKey'] = api_key if customer_id: + if type(customer_id) is not str: + raise ClientConfigurationError("customer_id must be a string") self.api_key['customerId'] = customer_id """dict to store API key(s) """ diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py index a2106ba541..af955b0550 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py @@ -97,48 +97,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -189,3 +147,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py index c3ba452cb0..45d124edfd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py @@ -351,6 +351,7 @@ def add_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi index 3f66aa7697..2caf7ddfc8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi @@ -342,6 +342,7 @@ class AddUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py index a085fc4c87..86986bf388 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py @@ -294,6 +294,7 @@ def get_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -348,6 +349,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi index 76b358eabd..b4d4d42ae2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi @@ -283,6 +283,7 @@ class GetAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py index 8fc9f8c331..7f4b8433a1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py @@ -292,6 +292,7 @@ def get_white_labeling( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi index b7861ddac6..4916073250 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi @@ -283,6 +283,7 @@ class GetWhiteLabelingRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py index c04675dff0..b3b4a0c738 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py @@ -362,6 +362,7 @@ def create_user_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi index 69a4322a9a..f11dc5a55a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class CreateUserFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py index 235abc7256..a93ce587e9 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py @@ -371,6 +371,7 @@ def delete_many( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi index 182f67b86d..a0d4cb6bfd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi @@ -360,6 +360,7 @@ class DeleteManyRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py index edce34b474..0cde98e54b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py @@ -362,6 +362,7 @@ def delete_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi index 346b07e758..ed024015ca 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class DeleteFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py index e9557430ba..0e57727add 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py @@ -357,6 +357,7 @@ def delete_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -421,6 +422,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi index fdca5fbb52..bf0ec9856a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py index 7910ff35fa..47ef692d57 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py @@ -359,6 +359,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -423,6 +424,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi index 26697b2ed1..194d823245 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py index cda04a5023..a98428a48d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py @@ -452,6 +452,7 @@ def get_documents( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -620,6 +621,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi index 82f31cf3ed..f5c39b652d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi @@ -441,6 +441,7 @@ class GetDocumentsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -609,6 +610,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py index fa43720b0b..1857466136 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py @@ -362,6 +362,7 @@ def fetch_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi index c16ed4320a..7da5391d1a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi @@ -351,6 +351,7 @@ class FetchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py index e1f1aeedc4..9102ce93a0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py @@ -378,6 +378,7 @@ def fetch_youtube_transcripts( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -450,6 +451,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi index 4dc01c1bd5..1210d71a69 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi @@ -367,6 +367,7 @@ class FetchYoutubeTranscriptsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -439,6 +440,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py index 6188e3d6d3..68be5b43a5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py @@ -257,6 +257,7 @@ def check( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -311,6 +312,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi index b93a5cef84..c37513c8c8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi @@ -252,6 +252,7 @@ class CheckRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -306,6 +307,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py index ce14dd256d..15556cccc2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py @@ -359,6 +359,7 @@ def list_confluence_pages( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi index dceff6d8c0..96a5fe2cc5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi @@ -348,6 +348,7 @@ class ListConfluencePagesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py index f066d09a71..2cc9d4037d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py @@ -413,6 +413,7 @@ def sync_confluence( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi index dae7c5783b..4e8f234c75 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi @@ -402,6 +402,7 @@ class SyncConfluenceRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py index 03315198af..1d254ec9f4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py @@ -413,6 +413,7 @@ def sync_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi index 0218b421a4..5ac5a8d90a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi @@ -402,6 +402,7 @@ class SyncFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py index e95129f3e5..438d321a78 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py @@ -404,6 +404,7 @@ def connect_freshdesk( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi index fc60b74309..c4131669a5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi @@ -393,6 +393,7 @@ class ConnectFreshdeskRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py index 5f29f72f13..462fee83a2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py @@ -398,6 +398,7 @@ def sync_gmail( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi index bd24219b05..a5c539360b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi @@ -387,6 +387,7 @@ class SyncGmailRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py index 1553396f34..82b93e8c68 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py @@ -291,6 +291,7 @@ def list_labels( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi index 574e8e2f2d..d4808e001e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi @@ -280,6 +280,7 @@ class ListLabelsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py index 7b86208e5c..06d19008b4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py @@ -368,6 +368,7 @@ def list_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -448,6 +449,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi index 9ada873e5f..b527a3dca5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi @@ -357,6 +357,7 @@ class ListDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -437,6 +438,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py index 3bc22043da..6c241127f5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py @@ -353,6 +353,7 @@ def sync_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi index 693fc6b901..777130cedd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi @@ -342,6 +342,7 @@ class SyncDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py index cf0aadb9d9..12974467a0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py @@ -434,6 +434,7 @@ def get_oauth_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -602,6 +603,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi index 02a57a8775..862acff67f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi @@ -423,6 +423,7 @@ class GetOauthUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -591,6 +592,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py index 2ff3a0409d..ee5ba6e5cd 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py @@ -404,6 +404,7 @@ def sync_outlook( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi index 9e1aec668a..044800b7d1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi @@ -393,6 +393,7 @@ class SyncOutlookRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py index 32f95f5d62..8875324408 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py @@ -291,6 +291,7 @@ def list_folders( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi index a2561e2a7a..865805aebc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi @@ -280,6 +280,7 @@ class ListFoldersRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py index 06b5fcd608..4e77986453 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py @@ -398,6 +398,7 @@ def sync_rss_feed( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi index b4f2224772..b09e42354b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi @@ -387,6 +387,7 @@ class SyncRssFeedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py index 4bf037d808..fb7f392aa3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py @@ -359,6 +359,7 @@ def create_aws_iam_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi index 4c723594f6..79afa2f0e9 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi @@ -348,6 +348,7 @@ class CreateAwsIamUserRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py index 00593c1e88..843e0fcc8a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py @@ -407,6 +407,7 @@ def sync_s3_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -535,6 +536,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi index 60e001e856..801e982974 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi @@ -396,6 +396,7 @@ class SyncS3FilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -524,6 +525,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py index 29a5e6ba97..88bc495ce7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py @@ -359,6 +359,7 @@ def toggle_user_features( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi index c30af2aeac..535f161d6f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi @@ -348,6 +348,7 @@ class ToggleUserFeaturesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py index 1be29c59e4..83f948d7b1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py @@ -292,6 +292,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi index cced7688ad..533208c04f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi @@ -283,6 +283,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py index af4a2e48a7..231012a2b8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py @@ -361,6 +361,7 @@ def get_parsed_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi index 0adabb1350..fad322dbc4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetParsedFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py index 75a641e301..74a7dcf779 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py @@ -359,6 +359,7 @@ def process_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -423,6 +424,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi index 4abb267c7d..1276ced736 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi @@ -348,6 +348,7 @@ class ProcessSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -412,6 +413,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py index a4a0e471bb..1d482b74f6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py @@ -361,6 +361,7 @@ def get_raw_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi index 46a8c43930..bbe9767c4b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetRawFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py index 01d7c4d352..77e4461026 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py @@ -365,6 +365,7 @@ def resync( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -445,6 +446,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi index b1036d310b..671a0913ef 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi @@ -354,6 +354,7 @@ class ResyncRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -434,6 +435,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py index 9fbca0ffaa..200e42e230 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py @@ -353,6 +353,7 @@ def revoke_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi index 17045520f0..a547134ef6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi @@ -342,6 +342,7 @@ class RevokeAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py index 51f2a96cd3..b0446441f8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py @@ -428,6 +428,7 @@ def scrape_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -580,6 +581,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi index 6804689067..51312f0e35 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi @@ -417,6 +417,7 @@ class ScrapeSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -569,6 +570,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py index 9cae2e6dcd..9be54dad09 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py @@ -362,6 +362,7 @@ def search_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi index a5d7bdded3..17d04d9493 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi @@ -351,6 +351,7 @@ class SearchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py index d3ba1bd9e1..981c03b61c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py @@ -389,6 +389,7 @@ def get_embeddings_and_chunks( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -485,6 +486,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi index cc02415d19..392b6143d5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi @@ -378,6 +378,7 @@ class GetEmbeddingsAndChunksRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -474,6 +475,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py index c925481db1..e489185e01 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py @@ -371,6 +371,7 @@ def upload_chunks_and_embeddings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi index f2a96c6946..6ca4f9916a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi @@ -360,6 +360,7 @@ class UploadChunksAndEmbeddingsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py index d33b565e42..b176fc3601 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py @@ -416,6 +416,7 @@ def upload_from_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -560,6 +561,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi index 63447dcae7..2362aedc72 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi @@ -405,6 +405,7 @@ class UploadFromUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -549,6 +550,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py index 2579dc20b2..330f1d4361 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py @@ -398,6 +398,7 @@ def upload_text( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi index 3df5f38644..59569ee31a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi @@ -387,6 +387,7 @@ class UploadTextRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py index 8dd18d5a26..fc668dfd15 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py @@ -608,6 +608,7 @@ def upload( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -746,6 +747,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi index ee1e8b24fa..0319520a3c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi @@ -597,6 +597,7 @@ class UploadRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -735,6 +736,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py index e2c6918e57..e0ee2e3d3c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py @@ -351,6 +351,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi index 681cb4c1bb..c72d7177e2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi @@ -342,6 +342,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py index a351b150f2..f0f9900e00 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py @@ -383,6 +383,7 @@ def query_user_data_sources( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -471,6 +472,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi index f83936aa72..c47c170d35 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi @@ -372,6 +372,7 @@ class QueryUserDataSourcesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py index eee7b8f4ee..8386563979 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py @@ -403,6 +403,7 @@ def query_user_files_deprecated( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -519,6 +520,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi index aa114dd86c..1c25b968a7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi @@ -392,6 +392,7 @@ class QueryUserFilesDeprecatedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -508,6 +509,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py index 79f7bce933..95f7462ae7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py @@ -401,6 +401,7 @@ def query_user_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -513,6 +514,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi index 2fe4823b6c..9a14d2b8a6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi @@ -390,6 +390,7 @@ class QueryUserFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -502,6 +503,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py index 2188240631..c240d52c83 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py @@ -348,6 +348,7 @@ def scrape_web( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -412,6 +413,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi index 0c3a3687a0..f66f992a75 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi @@ -337,6 +337,7 @@ class ScrapeWebRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -401,6 +402,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py index 3f2273b517..fc2016aa79 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py @@ -381,6 +381,7 @@ def urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -469,6 +470,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi index 93428441ae..a39501dd99 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi @@ -372,6 +372,7 @@ class UrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py index c1eb1c998c..a2f3497071 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1843,7 +1877,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1878,7 +1912,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1994,6 +2028,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2056,39 +2091,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py index 54b9dba341..b0f05eac52 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py @@ -22,6 +22,7 @@ class RequiredChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[SingleChunksAndEmbeddingsUploadInput] + class OptionalChunksAndEmbeddingsUploadInput(TypedDict, total=False): overwrite_existing: bool diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py index 2d09407e3c..2f790977d4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py @@ -19,6 +19,7 @@ class RequiredEmbeddingsAndChunksFilters(TypedDict): user_file_id: int + class OptionalEmbeddingsAndChunksFilters(TypedDict, total=False): embedding_model: typing.Optional[EmbeddingGeneratorsNullable] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py index 196596694b..b7837260ef 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py @@ -22,6 +22,7 @@ class RequiredEmbeddingsAndChunksQueryInput(TypedDict): filters: EmbeddingsAndChunksFilters + class OptionalEmbeddingsAndChunksQueryInput(TypedDict, total=False): pagination: Pagination diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py index 3ebb97608a..397a2bd7d6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py @@ -21,6 +21,7 @@ class RequiredFreshDeskConnectRequest(TypedDict): api_key: str + class OptionalFreshDeskConnectRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py index da727a2b5b..9286d1487c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py @@ -29,6 +29,7 @@ class RequiredGetEmbeddingDocumentsBody(TypedDict): # Number of related chunks to return. k: int + class OptionalGetEmbeddingDocumentsBody(TypedDict, total=False): tags: typing.Optional[GetEmbeddingDocumentsBodyTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py index 5d1d23c66c..44979438b5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py @@ -19,6 +19,7 @@ class RequiredGmailSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalGmailSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py index 8dc016b743..7598773465 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py @@ -19,6 +19,7 @@ class RequiredListDataSourceItemsRequest(TypedDict): data_source_id: int + class OptionalListDataSourceItemsRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py index 8715645d67..7eeff13db2 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py @@ -18,6 +18,7 @@ class RequiredListRequest(TypedDict): data_source_id: int + class OptionalListRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py index 82b13ced32..9aacadf64a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py @@ -20,6 +20,7 @@ class RequiredOAuthURLRequest(TypedDict): service: DataSourceType + class OptionalOAuthURLRequest(TypedDict, total=False): tags: typing.Union[bool, date, datetime, dict, float, int, list, str, None] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py index f9c3ce6c0a..9c498c370c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py @@ -19,6 +19,7 @@ class RequiredOutlookSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalOutlookSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py index 477993e3c0..208765ba7c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py @@ -19,6 +19,7 @@ class RequiredRawTextInput(TypedDict): contents: str + class OptionalRawTextInput(TypedDict, total=False): name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py index f6cec1e81d..d343c6672f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py @@ -18,6 +18,7 @@ class RequiredResyncFileQueryInput(TypedDict): file_id: int + class OptionalResyncFileQueryInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py index 6f4459e1d3..b82314f9d7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py @@ -19,6 +19,7 @@ class RequiredRSSFeedInput(TypedDict): url: str + class OptionalRSSFeedInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py index 309f5e04d6..326e013fcb 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py @@ -20,6 +20,7 @@ class RequiredS3FileSyncInput(TypedDict): ids: typing.List[S3GetFileInput] + class OptionalS3FileSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py index b9b527ca92..20388cc53b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py @@ -21,6 +21,7 @@ class RequiredSingleChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[ChunksAndEmbeddings] + class OptionalSingleChunksAndEmbeddingsUploadInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py index c04ad96066..0410ccb058 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py @@ -22,6 +22,7 @@ class RequiredSitemapScrapeRequest(TypedDict): url: str + class OptionalSitemapScrapeRequest(TypedDict, total=False): tags: typing.Optional[SitemapScrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py index a79a55db68..42565acca0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py @@ -22,6 +22,7 @@ class RequiredSyncFilesRequest(TypedDict): ids: SyncFilesRequestIds + class OptionalSyncFilesRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py index e3b523aa4d..a247797ba1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py @@ -19,6 +19,7 @@ class RequiredUploadFileFromUrlInput(TypedDict): url: str + class OptionalUploadFileFromUrlInput(TypedDict, total=False): file_name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py index 794562fec2..bfc385925d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py @@ -22,6 +22,7 @@ class RequiredWebscrapeRequest(TypedDict): url: str + class OptionalWebscrapeRequest(TypedDict, total=False): tags: typing.Optional[WebscrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py index 6c773b397a..a21e7334ba 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_circular_reference_2.pydantic.has_optional_var import HasOptionalVar +from python_circular_reference_2.pydantic.has_required_var import HasRequiredVar + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py index 5082d7f42a..40a50e0e04 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py index 6c30566626..6307584568 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py index 4994f9dce9..d914e8ae77 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi index 11605b181b..9bd6588569 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py index f11c371839..609402538c 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py index e0c4d31094..ff3475cbe7 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,12 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_circular_reference.pydantic.item import Item +from python_circular_reference.pydantic.test_fetch_response import TestFetchResponse +from python_circular_reference.pydantic.test_infinite_loop import TestInfiniteLoop + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +101,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +127,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +144,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py index f9d60f279c..c0da1d1d36 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py index 36c0fba336..75e31f390a 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py index dd8b951ead..0303fec928 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi index 4e300f7bb0..2c83362f3a 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py index 41987134c5..4b3c492e81 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py index a7a1874997..ab9050d4be 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py @@ -22,6 +22,7 @@ class RequiredTestFetchResponse(TypedDict): required: 'TestInfiniteLoop' + class OptionalTestFetchResponse(TypedDict, total=False): value: 'TestInfiniteLoop' diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py index 9e38eab9be..f59f4a1748 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py @@ -21,6 +21,7 @@ class RequiredTestInfiniteLoop(TypedDict): required: 'TestFetchResponse' + class OptionalTestInfiniteLoop(TypedDict, total=False): value: 'TestFetchResponse' diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/.coverage b/generator/konfig-integration-tests/sdks/python-decentro/python/.coverage index 37b754c458..5fa5e7fc9a 100644 Binary files a/generator/konfig-integration-tests/sdks/python-decentro/python/.coverage and b/generator/konfig-integration-tests/sdks/python-decentro/python/.coverage differ diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/api_client.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/api_client.py index 4242b060f5..b0c595339c 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,29 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from decentro_in_collections_client.pydantic.generate_payment_link400_response import GeneratePaymentLink400Response +from decentro_in_collections_client.pydantic.generate_payment_link_request import GeneratePaymentLinkRequest +from decentro_in_collections_client.pydantic.generate_payment_link_response import GeneratePaymentLinkResponse +from decentro_in_collections_client.pydantic.generate_payment_link_response_data import GeneratePaymentLinkResponseData +from decentro_in_collections_client.pydantic.generate_payment_link_response_data_psp_uri import GeneratePaymentLinkResponseDataPspUri +from decentro_in_collections_client.pydantic.get_transaction_status_response import GetTransactionStatusResponse +from decentro_in_collections_client.pydantic.get_transaction_status_response_data import GetTransactionStatusResponseData +from decentro_in_collections_client.pydantic.get_transaction_status_response_error import GetTransactionStatusResponseError +from decentro_in_collections_client.pydantic.issue_collect_request400_response import IssueCollectRequest400Response +from decentro_in_collections_client.pydantic.issue_collect_request_request import IssueCollectRequestRequest +from decentro_in_collections_client.pydantic.issue_collect_request_response import IssueCollectRequestResponse +from decentro_in_collections_client.pydantic.issue_collect_request_response_data import IssueCollectRequestResponseData +from decentro_in_collections_client.pydantic.issue_upi_refund400_response import IssueUpiRefund400Response +from decentro_in_collections_client.pydantic.issue_upi_refund_request import IssueUpiRefundRequest +from decentro_in_collections_client.pydantic.issue_upi_refund_response import IssueUpiRefundResponse +from decentro_in_collections_client.pydantic.issue_upi_refund_response_data import IssueUpiRefundResponseData +from decentro_in_collections_client.pydantic.validate_upi_handle400_response import ValidateUpiHandle400Response +from decentro_in_collections_client.pydantic.validate_upi_handle_request import ValidateUpiHandleRequest +from decentro_in_collections_client.pydantic.validate_upi_handle_response import ValidateUpiHandleResponse +from decentro_in_collections_client.pydantic.validate_upi_handle_response_data import ValidateUpiHandleResponseData + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +118,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +144,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +161,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py index 743419b4a4..e8da96ad72 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py @@ -134,18 +134,26 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if client_id: + if type(client_id) is not str: + raise ClientConfigurationError("client_id must be a string") self.api_key['client_id'] = client_id else: raise ClientConfigurationError('API Key "client_id" is required') if client_secret: + if type(client_secret) is not str: + raise ClientConfigurationError("client_secret must be a string") self.api_key['client_secret'] = client_secret else: raise ClientConfigurationError('API Key "client_secret" is required') if module_secret: + if type(module_secret) is not str: + raise ClientConfigurationError("module_secret must be a string") self.api_key['module_secret'] = module_secret else: raise ClientConfigurationError('API Key "module_secret" is required') if provider_secret: + if type(provider_secret) is not str: + raise ClientConfigurationError("provider_secret must be a string") self.api_key['provider_secret'] = provider_secret else: raise ClientConfigurationError('API Key "provider_secret" is required') diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py index 9fc3ebf15f..c244c63d07 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py index bc946009f3..30244c89e9 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py @@ -389,6 +389,7 @@ def issue_collect_request( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, @@ -501,6 +502,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi index bfc2e47d03..31382695ed 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi @@ -377,6 +377,7 @@ class IssueCollectRequestRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, @@ -489,6 +490,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py index 40bf7792f3..31a3e51600 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py @@ -357,6 +357,7 @@ def get_transaction_status( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, @@ -429,6 +430,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi index 5f08886398..10f932a949 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi @@ -343,6 +343,7 @@ class GetTransactionStatusRaw(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py index 21e4bf0f4e..30878cbc3b 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py @@ -401,6 +401,7 @@ def generate_payment_link( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, @@ -529,6 +530,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi index f9bbd9f8a8..aca46ae09d 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi @@ -389,6 +389,7 @@ class GeneratePaymentLinkRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, @@ -517,6 +518,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py index c410a199a7..8bc2587346 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py @@ -377,6 +377,7 @@ def issue_upi_refund( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, @@ -473,6 +474,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi index 86d4153a42..46bf69e2f9 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi @@ -365,6 +365,7 @@ class IssueUpiRefundRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, @@ -461,6 +462,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py index a359a34e2a..c3f2e638b6 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py @@ -371,6 +371,7 @@ def validate_upi_handle( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, @@ -459,6 +460,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi index bfa2087056..c94639172d 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi @@ -359,6 +359,7 @@ class ValidateUpiHandleRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, @@ -447,6 +448,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py index d2dbf8e99e..26448662fa 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py index 1367449276..9738fa2e44 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py @@ -27,6 +27,7 @@ class RequiredGeneratePaymentLinkRequest(TypedDict): generate_qr: int + class OptionalGeneratePaymentLinkRequest(TypedDict, total=False): expiry_time: int diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py index 7a809c1a20..9875c24c6c 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py @@ -27,6 +27,7 @@ class RequiredIssueCollectRequestRequest(TypedDict): purpose_message: str + class OptionalIssueCollectRequestRequest(TypedDict, total=False): expiry_time: int diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py index adb1d24cfa..ffa7047201 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py @@ -19,6 +19,7 @@ class RequiredIssueUpiRefundRequest(TypedDict): reference_id: str + class OptionalIssueUpiRefundRequest(TypedDict, total=False): transaction_id: str diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py index 4993c35df6..4d294647f4 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py @@ -21,6 +21,7 @@ class RequiredValidateUpiHandleRequest(TypedDict): upi_id: str + class OptionalValidateUpiHandleRequest(TypedDict, total=False): type: str diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py index 1fdd3ba457..4c1b28994d 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_enum_parameter.pydantic.problematic_enum import ProblematicEnum + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py index 1ff05a82a1..181f006fc1 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py index 391da19e12..f1d3792c00 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py index b9b5480162..64abfdc4be 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py @@ -336,6 +336,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) @@ -400,6 +401,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi index 344ab11d83..45ab31812c 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi @@ -328,6 +328,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) @@ -392,6 +393,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py index bbec742e65..e477835a97 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py index 9a81ef97fa..e7e24ab0a7 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_ignore_pydantic_protected_namespaces.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py index 69fded6cbe..3e5a4a06db 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py index 7167344126..9b70716e1d 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py index 043fd9fc5f..648bd5a9d9 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi index 5f61efdb59..b4eb8c833e 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py index 0fff7487d1..455b15af72 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py index 3c76a21330..41808cea20 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,18 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_invalid_response.pydantic.dict_instead_of_list_or_scalar import DictInsteadOfListOrScalar +from python_invalid_response.pydantic.invalid_array import InvalidArray +from python_invalid_response.pydantic.invalid_array_array import InvalidArrayArray +from python_invalid_response.pydantic.invalid_object import InvalidObject +from python_invalid_response.pydantic.invalid_object_object import InvalidObjectObject +from python_invalid_response.pydantic.invalid_scalar import InvalidScalar +from python_invalid_response.pydantic.list_instead_of_scalar import ListInsteadOfScalar +from python_invalid_response.pydantic.object_instead_of_scalar import ObjectInsteadOfScalar +from python_invalid_response.pydantic.only_one_property_is_invalid import OnlyOnePropertyIsInvalid + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +107,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +133,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +150,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py index f44a7760f6..16af52980d 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py index 8670775eff..0f1b6e1607 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py index 8dc7d18a53..02205ac471 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py @@ -266,6 +266,7 @@ def dict_instead_of_list_or_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi index bb2b439486..edc14dd49d 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi @@ -258,6 +258,7 @@ class DictInsteadOfListOrScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py index 7c18655b6c..6cbaeec7f7 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py @@ -266,6 +266,7 @@ def invalid_array( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi index 28f407ef5a..c966a4eec8 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi @@ -258,6 +258,7 @@ class InvalidArrayRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py index 4f565ba979..af34ddcd46 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py @@ -266,6 +266,7 @@ def invalid_object( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi index 3c26381324..10dfb6ba00 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi @@ -258,6 +258,7 @@ class InvalidObjectRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py index 59ee61781c..60b66d0191 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py @@ -266,6 +266,7 @@ def invalid_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi index 97673fab17..890b3c74fb 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi @@ -258,6 +258,7 @@ class InvalidScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py index b09e72383a..0a12d5c4a9 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py @@ -263,6 +263,7 @@ def list_instead_of_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( @@ -317,6 +318,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi index 689a0bfa15..c746f1d136 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi @@ -255,6 +255,7 @@ class ListInsteadOfScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py index 6d6d6e1bce..9bbcd6f5e3 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py @@ -263,6 +263,7 @@ def object_instead_of_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( @@ -317,6 +318,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi index 76c108bff8..e046a9dd45 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi @@ -255,6 +255,7 @@ class ObjectInsteadOfScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py index c4dc41b59d..015720e83d 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py @@ -266,6 +266,7 @@ def only_one_property_is_invalid( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi index babf9198d2..f7b5f0df85 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi @@ -258,6 +258,7 @@ class OnlyOnePropertyIsInvalidRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py index 28208a3ab4..1f9060f4ef 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py index af22c07e2b..9c00972167 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_nested_array_items_ref_in_any_of.pydantic.simple_schema import SimpleSchema +from python_nested_array_items_ref_in_any_of.pydantic.test_fetch_request import TestFetchRequest + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py index 9526643f17..d1d0e4c82d 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py index 181cc75b55..ffe8f4a16e 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py index 0bc64d7f95..13b9367d61 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py @@ -327,6 +327,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -391,6 +392,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi index c57498c73d..c3289eb317 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi @@ -319,6 +319,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -383,6 +384,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py index de02febe57..1babcfe89a 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py index 6d04f5e5d9..93a7175915 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,47 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from newscatcherapi_client.pydantic.additional_source_info import AdditionalSourceInfo +from newscatcherapi_client.pydantic.author_search_request import AuthorSearchRequest +from newscatcherapi_client.pydantic.authors_get_response import AuthorsGetResponse +from newscatcherapi_client.pydantic.authors_post_response import AuthorsPostResponse +from newscatcherapi_client.pydantic.cluster import Cluster +from newscatcherapi_client.pydantic.cluster_articles import ClusterArticles +from newscatcherapi_client.pydantic.clustering_search_response import ClusteringSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_article_result import DtoResponsesAuthorSearchResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_author_search_response_failed_search_response import DtoResponsesAuthorSearchResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response import DtoResponsesAuthorSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response_articles import DtoResponsesAuthorSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_article_result import DtoResponsesMoreLikeThisResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_failed_search_response import DtoResponsesMoreLikeThisResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response import DtoResponsesMoreLikeThisResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response_articles import DtoResponsesMoreLikeThisResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response import DtoResponsesSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response_articles import DtoResponsesSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.http_validation_error import HTTPValidationError +from newscatcherapi_client.pydantic.latest_headlines_get_response import LatestHeadlinesGetResponse +from newscatcherapi_client.pydantic.latest_headlines_post_response import LatestHeadlinesPostResponse +from newscatcherapi_client.pydantic.latest_headlines_request import LatestHeadlinesRequest +from newscatcherapi_client.pydantic.latest_headlines_response import LatestHeadlinesResponse +from newscatcherapi_client.pydantic.latest_headlines_response_articles import LatestHeadlinesResponseArticles +from newscatcherapi_client.pydantic.more_like_this_request import MoreLikeThisRequest +from newscatcherapi_client.pydantic.search_get_response import SearchGetResponse +from newscatcherapi_client.pydantic.search_post_response import SearchPostResponse +from newscatcherapi_client.pydantic.search_request import SearchRequest +from newscatcherapi_client.pydantic.search_similar_get_response import SearchSimilarGetResponse +from newscatcherapi_client.pydantic.search_similar_post_response import SearchSimilarPostResponse +from newscatcherapi_client.pydantic.search_url_request import SearchURLRequest +from newscatcherapi_client.pydantic.similar_document import SimilarDocument +from newscatcherapi_client.pydantic.source_info import SourceInfo +from newscatcherapi_client.pydantic.source_response import SourceResponse +from newscatcherapi_client.pydantic.source_response_sources import SourceResponseSources +from newscatcherapi_client.pydantic.sources_request import SourcesRequest +from newscatcherapi_client.pydantic.subscription_response import SubscriptionResponse +from newscatcherapi_client.pydantic.validation_error import ValidationError +from newscatcherapi_client.pydantic.validation_error_loc import ValidationErrorLoc + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +136,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +162,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +179,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py index c8b773047b..f19b86262b 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py @@ -139,6 +139,8 @@ def __init__(self, host=None, else: raise ClientConfigurationError('API Key "apiKey" is required') if x_api_token: + if type(x_api_token) is not str: + raise ClientConfigurationError("x_api_token must be a string") self.api_key['apiKey'] = x_api_token elif api_key is None: raise ClientConfigurationError('API Key "apiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py index c2747cb02e..a1fa2162fd 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py index 6631a59f33..23796833d6 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py @@ -1077,6 +1077,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -1445,6 +1446,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi index ef087db432..5df23dee2a 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi @@ -1056,6 +1056,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -1424,6 +1425,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py index cc7fc9e979..31e770aca6 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py @@ -580,6 +580,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -948,6 +949,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi index bfffe10b10..1d92a0cddb 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi @@ -571,6 +571,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -939,6 +940,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py index 94d55cd9f5..2a7d62015e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py @@ -1000,6 +1000,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1368,6 +1369,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi index b337ad52a2..ab18dab479 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi @@ -979,6 +979,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1347,6 +1348,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py index a6f60a9354..6503be9642 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py @@ -580,6 +580,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -948,6 +949,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi index 0bc7dd9e3f..49eb8e3556 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi @@ -571,6 +571,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -939,6 +940,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py index 0c7d8ab2f1..13f69b8858 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py @@ -1221,6 +1221,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1661,6 +1662,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi index 4f28416014..7a026a030d 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi @@ -1200,6 +1200,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1640,6 +1641,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py index 713678dfe5..ec81cc7748 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py @@ -634,6 +634,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -1074,6 +1075,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi index 4ce7f28d04..726ec3e9e0 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi @@ -625,6 +625,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -1065,6 +1066,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py index dc878b8a54..6fb41645ee 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py @@ -424,6 +424,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, @@ -512,6 +513,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi index 5be3abdb29..2bce33d817 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi @@ -409,6 +409,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, @@ -497,6 +498,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py index be3fa4f00a..04011706b5 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py @@ -370,6 +370,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, @@ -458,6 +459,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi index eb32bbe31b..ee917d9589 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi @@ -361,6 +361,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, @@ -449,6 +450,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py index 658efa959b..1162369f0b 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py @@ -1101,6 +1101,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1477,6 +1478,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi index bf677d90dc..e497735b97 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi @@ -1077,6 +1077,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1453,6 +1454,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py index d4373d1578..02f621a117 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py @@ -586,6 +586,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -962,6 +963,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi index 0185b47a0c..479a5046da 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi @@ -577,6 +577,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -953,6 +954,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py index 3df224ebd0..d88e1b72bb 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py @@ -472,6 +472,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -592,6 +593,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi index 0e74345841..8ba5f42111 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi @@ -463,6 +463,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -583,6 +584,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py index 2de77029a5..91a48ff853 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py @@ -394,6 +394,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -514,6 +515,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi index 1789ed892f..b2ae1b226f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi @@ -385,6 +385,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -505,6 +506,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py index 9dfbcd2724..05b1d143cc 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py @@ -293,6 +293,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -347,6 +348,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi index fb5fe425fb..070dc33705 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi @@ -284,6 +284,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -338,6 +339,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py index 9b1d07b764..77e1d967ac 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py @@ -293,6 +293,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -347,6 +348,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi index 30c95e31f6..46e8d6a374 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi @@ -284,6 +284,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -338,6 +339,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py index ed34decee7..f24792f972 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/.coverage b/generator/konfig-integration-tests/sdks/python-newscatcher/python/.coverage index 378ad6b4a0..35d29653db 100644 Binary files a/generator/konfig-integration-tests/sdks/python-newscatcher/python/.coverage and b/generator/konfig-integration-tests/sdks/python-newscatcher/python/.coverage differ diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py index 6fba226abc..538ca03a58 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,49 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from newscatcherapi_client.pydantic.author_search_request import AuthorSearchRequest +from newscatcherapi_client.pydantic.authors_get_response import AuthorsGetResponse +from newscatcherapi_client.pydantic.authors_post_response import AuthorsPostResponse +from newscatcherapi_client.pydantic.cluster import Cluster +from newscatcherapi_client.pydantic.cluster_articles import ClusterArticles +from newscatcherapi_client.pydantic.clustering_search_response import ClusteringSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_article_result import DtoResponsesAuthorSearchResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_author_search_response_failed_search_response import DtoResponsesAuthorSearchResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response import DtoResponsesAuthorSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response_articles import DtoResponsesAuthorSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_latest_headlines_response_article_result import DtoResponsesLatestHeadlinesResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_article_result import DtoResponsesMoreLikeThisResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_failed_search_response import DtoResponsesMoreLikeThisResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response import DtoResponsesMoreLikeThisResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response_articles import DtoResponsesMoreLikeThisResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_search_response_article_result import DtoResponsesSearchResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_search_response_failed_search_response import DtoResponsesSearchResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response import DtoResponsesSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response_articles import DtoResponsesSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.failed_latest_headlines_response import FailedLatestHeadlinesResponse +from newscatcherapi_client.pydantic.http_validation_error import HTTPValidationError +from newscatcherapi_client.pydantic.latest_headlines_get_response import LatestHeadlinesGetResponse +from newscatcherapi_client.pydantic.latest_headlines_post_response import LatestHeadlinesPostResponse +from newscatcherapi_client.pydantic.latest_headlines_request import LatestHeadlinesRequest +from newscatcherapi_client.pydantic.latest_headlines_response import LatestHeadlinesResponse +from newscatcherapi_client.pydantic.latest_headlines_response_articles import LatestHeadlinesResponseArticles +from newscatcherapi_client.pydantic.more_like_this_request import MoreLikeThisRequest +from newscatcherapi_client.pydantic.search_get_response import SearchGetResponse +from newscatcherapi_client.pydantic.search_post_response import SearchPostResponse +from newscatcherapi_client.pydantic.search_request import SearchRequest +from newscatcherapi_client.pydantic.search_similar_get_response import SearchSimilarGetResponse +from newscatcherapi_client.pydantic.search_similar_post_response import SearchSimilarPostResponse +from newscatcherapi_client.pydantic.similar_document import SimilarDocument +from newscatcherapi_client.pydantic.source_response import SourceResponse +from newscatcherapi_client.pydantic.source_response_sources import SourceResponseSources +from newscatcherapi_client.pydantic.sources_request import SourcesRequest +from newscatcherapi_client.pydantic.subscription_response import SubscriptionResponse +from newscatcherapi_client.pydantic.user_input import UserInput +from newscatcherapi_client.pydantic.validation_error import ValidationError +from newscatcherapi_client.pydantic.validation_error_loc import ValidationErrorLoc + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +138,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +164,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +181,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py index c5694211a6..512b78e0f9 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py @@ -139,6 +139,8 @@ def __init__(self, host=None, else: raise ClientConfigurationError('API Key "apiKey" is required') if x_api_token: + if type(x_api_token) is not str: + raise ClientConfigurationError("x_api_token must be a string") self.api_key['apiKey'] = x_api_token elif api_key is None: raise ClientConfigurationError('API Key "apiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py index 4c56077b0b..be82aa1283 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py index f23f5453c5..2c2f047679 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py @@ -981,6 +981,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, @@ -1301,6 +1302,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi index d1c9d6f6f6..69784c2bc8 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi @@ -960,6 +960,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, @@ -1280,6 +1281,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py index 3be687499d..62d2544e9b 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py @@ -544,6 +544,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, @@ -864,6 +865,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi index 613e0e347f..c04629a055 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi @@ -535,6 +535,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, @@ -855,6 +856,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py index fbc6d41f76..5ac9b4dc46 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py @@ -904,6 +904,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1224,6 +1225,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi index 3a44b7a44a..e80f833e50 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi @@ -883,6 +883,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1203,6 +1204,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py index 4990ab679e..6864c2f9ef 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py @@ -544,6 +544,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -864,6 +865,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi index 7286d27c59..4ecedfbf5e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi @@ -535,6 +535,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -855,6 +856,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py index f034dff4f5..25010965ee 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py @@ -1093,6 +1093,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1469,6 +1470,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi index 3496cd4927..d7e4edfb50 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi @@ -1072,6 +1072,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1448,6 +1449,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py index b602b49091..8b6a9db05f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py @@ -586,6 +586,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -962,6 +963,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi index 6d94f7869c..7777b7b259 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi @@ -577,6 +577,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -953,6 +954,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py index 2540c18652..fdc7f1e3ae 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py @@ -1053,6 +1053,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1405,6 +1406,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi index 743758a767..e928e24436 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi @@ -1029,6 +1029,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1381,6 +1382,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py index d0530592ec..1c1b1c7425 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py @@ -568,6 +568,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -920,6 +921,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi index 6bcdb585e5..0991513c70 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi @@ -559,6 +559,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -911,6 +912,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py index 8f55cadcab..f1fcd10835 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py @@ -376,6 +376,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -448,6 +449,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi index a9038a65dd..97326f8212 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi @@ -367,6 +367,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -439,6 +440,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py index bde275aa3a..a2a8db4690 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py @@ -358,6 +358,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -430,6 +431,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi index f3f3ac07b9..4581eb23f7 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi @@ -349,6 +349,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -421,6 +422,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py index 491d179de3..f23220ef90 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py @@ -293,6 +293,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -347,6 +348,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi index 43e448df42..f9f81862fe 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi @@ -284,6 +284,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -338,6 +339,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py index 188d5198d7..b70c6d5fbf 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py @@ -293,6 +293,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -347,6 +348,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi index dc482c91f0..56bb14970c 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi @@ -284,6 +284,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -338,6 +339,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py index 7ef6c3ce0c..0d7920fe24 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py index 4b823f576e..999ba62f8e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py @@ -19,6 +19,7 @@ class RequiredAuthorSearchRequest(TypedDict): author_name: str + class OptionalAuthorSearchRequest(TypedDict, total=False): sources: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py index 7e5d656efc..269f5472c2 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py @@ -32,6 +32,7 @@ class RequiredClusteringSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalClusteringSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py index aaedf1377e..91bf96588d 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py @@ -35,6 +35,7 @@ class RequiredDtoResponsesAuthorSearchResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesAuthorSearchResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py index 9b2fc02230..82f894f986 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py @@ -20,6 +20,7 @@ class RequiredDtoResponsesAuthorSearchResponseFailedSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesAuthorSearchResponseFailedSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py index 0a6804cad3..f29a1413ad 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py @@ -30,6 +30,7 @@ class RequiredDtoResponsesAuthorSearchResponseSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesAuthorSearchResponseSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py index 3ff01435c3..a1ea47e3a4 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py @@ -33,6 +33,7 @@ class RequiredDtoResponsesLatestHeadlinesResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesLatestHeadlinesResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py index 197888ac7d..ae56eb52fd 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py @@ -36,6 +36,7 @@ class RequiredDtoResponsesMoreLikeThisResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesMoreLikeThisResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py index c4ac68e127..8700463ca3 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py @@ -20,6 +20,7 @@ class RequiredDtoResponsesMoreLikeThisResponseFailedSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesMoreLikeThisResponseFailedSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py index 5487fe83bb..97faed9a0f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py @@ -30,6 +30,7 @@ class RequiredDtoResponsesMoreLikeThisResponseSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesMoreLikeThisResponseSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py index 32ad12dba5..31162354ff 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py @@ -33,6 +33,7 @@ class RequiredDtoResponsesSearchResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesSearchResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py index 87b5836e4a..bb02f34d69 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py @@ -20,6 +20,7 @@ class RequiredDtoResponsesSearchResponseFailedSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesSearchResponseFailedSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py index 1b92e7cc3a..cd65eeb414 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py @@ -30,6 +30,7 @@ class RequiredDtoResponsesSearchResponseSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesSearchResponseSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py index d381a3382a..13739c66b6 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py @@ -20,6 +20,7 @@ class RequiredFailedLatestHeadlinesResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalFailedLatestHeadlinesResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py index e3341a8ce8..161161e890 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py @@ -30,6 +30,7 @@ class RequiredLatestHeadlinesResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalLatestHeadlinesResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py index 4a48faff9c..197a4573a9 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py @@ -19,6 +19,7 @@ class RequiredMoreLikeThisRequest(TypedDict): q: str + class OptionalMoreLikeThisRequest(TypedDict, total=False): search_in: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py index 91db82dae1..ba631ccd76 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py @@ -19,6 +19,7 @@ class RequiredSearchRequest(TypedDict): q: str + class OptionalSearchRequest(TypedDict, total=False): search_in: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py index 38df50ee02..049eafe9de 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py @@ -21,6 +21,7 @@ class RequiredSubscriptionResponse(TypedDict): plan_name: str + class OptionalSubscriptionResponse(TypedDict, total=False): calls_per_seconds: int diff --git a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py index 4d305033f9..d995d7d20f 100644 --- a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py index ba01d9bf79..05bbb8fa11 100644 --- a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py @@ -1878,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1913,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py index 745403f72a..f6d40a8a5c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_additional_properties_anyof.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py index 5c9448fcc4..6b452acda1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py index c6f5c0ce08..2bbb9ddccc 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py index fbb45cdb1b..42d4a4500d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi index 796e5b7acc..69291593db 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py index fecc25f382..d4ef81d486 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py index ed32792082..39b25fb3cb 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_any_schema_dict_response.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py index aa8008fa54..edfdfb105a 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py index 91dddf4910..7631a5ecda 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py index dc09c0a870..d08037062d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi index f391414641..6eeed6b7e9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py index 2266338d6f..cd36695b74 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py index 64cdc7837f..ac5c33f837 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_array_with_object.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py index f4e46a4901..35d99b2b38 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py index bca13f9e7e..4760209117 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py index cae0d5ce18..2445df68d2 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi index 1453d6aa1d..d2aeceb052 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py index 665648adf6..05a0d7cb7e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py index 405c1e1da4..6c7f9bae23 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py index 795beab8f6..bbdd4c484b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py index 4e28290d63..acf7059bfa 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py index b3c6e3dfdf..c53f8ec7b1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py @@ -247,6 +247,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -295,6 +296,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi index 74042da829..c68ed20478 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi @@ -239,6 +239,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -287,6 +288,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py index 51536b30c7..e3c7ba9740 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py index ff91aa68ea..437e3a2a34 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_enum_str.pydantic.enum import Enum +from python_pydantic_enum_str.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py index dabaaabe06..2367af2d18 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py index 92e2393029..c1d2360f10 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py index 525a2a31f3..69837afbe7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi index 8a45d74301..dd0570171d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py index 0b83bb38ce..f6c045eef8 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py index 5314ba5230..6f02e2aec4 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_free_form_object_property.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py index 900bd8e154..fc99ee69d1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py index b26b805e63..3a026e06d3 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py index b723475ec1..bbcb506b7f 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi index 5bd0db8f05..2556c5785a 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py index 5b7c280158..454316d854 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py index bfee8fce9b..15211ea877 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py index 92c0514fef..2bb1c95302 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py index 3440fe189f..6272c4975b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py index ff0d4f096c..b0f7f3d9e9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py @@ -333,6 +333,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -397,6 +398,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi index 8d905a9f13..6aa9cdee93 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi @@ -325,6 +325,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -389,6 +390,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py index e988849236..8cf44aeecc 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py index a417e20dc8..1ee6926928 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_list_in_union.pydantic.obj import Obj +from python_pydantic_list_in_union.pydantic.response import Response + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py index 802b66b5d8..c575f4b00f 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py index 25021e0f6a..cbc239a687 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py index 7762e1ea83..f788ce7e17 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi index 0f601f4129..23235da1cc 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py index 354624dbb1..28c17e77ac 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py index 50e0e3d132..566535b6b3 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_list_response.pydantic.test_fetch_response import TestFetchResponse +from python_pydantic_list_response.pydantic.test_fetch_response_item import TestFetchResponseItem + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py index 5f68c3a3bd..dbba3a1e82 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py index b10ab1b624..e938a3b8f0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py index cf9eeb80d6..ddfed16931 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi index 5205841015..f281209c28 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py index 57e845836a..5c863a6856 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py index 3b86e25632..ecdf7fb969 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_nested_union_with_list_and_str.pydantic.generic_image_content import GenericImageContent +from python_pydantic_nested_union_with_list_and_str.pydantic.generic_text_content import GenericTextContent +from python_pydantic_nested_union_with_list_and_str.pydantic.test_chat_message import TestChatMessage +from python_pydantic_nested_union_with_list_and_str.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py index 43eba7c674..f63c429e72 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py index 39c26ba20b..8584383e46 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py index fa1ee406ef..0c62129578 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi index 05fcdb2af8..40f0b03cb5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py index 8e411826f5..3b34e28de5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py index 7f250bfbfe..3a81ebfa79 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_nullable_string.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py index 3f9a271dff..001ffe631f 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py index 3f177af953..dc6ac6a3d1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py index e70ff01b9c..4a6fbe8c5c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi index 90c73508bb..60460d7e77 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py index 52c0b0f85e..1848f6e082 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py index cfab482152..ffb201b04f 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py index 1b50f89122..4790cf350e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py index 0123d37188..86141ed0e0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py index d0e424bac8..18d96d952b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi index 3c3bfcc730..9707e677cf 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py index d4822485c4..e4884fed72 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py index e799d75793..c792b19e90 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,12 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_recursively_convert_to_models.pydantic.inner import Inner +from python_pydantic_recursively_convert_to_models.pydantic.list_inner import ListInner +from python_pydantic_recursively_convert_to_models.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +101,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +127,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +144,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py index 55ce6ab8f8..e2aaf9ddf0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py index bc380bdd1a..25a1ff1687 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py index 1476a3a381..a3a072cb35 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py @@ -268,6 +268,7 @@ def list( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi index f6ce87b981..f144077f9a 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi @@ -260,6 +260,7 @@ class ListRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py index 7f5eda9495..8d02161d20 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi index 86bade06ad..f4a9309157 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py index 17d9c6a043..cf48a761a5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py index c3475a547e..2dae1b4025 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_reserved_namespace_model.pydantic.inner import Inner +from python_pydantic_reserved_namespace_model.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py index df2be016fb..04074def59 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py index eb3b64ecf7..51d8c01c75 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py index b941788efd..82d4cd030a 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi index 0e118b3199..e82f8d6197 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py index dbd27b067f..04dccf7e34 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py index 4592e81a70..11925e3b64 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_response_as_param.pydantic.attack import Attack +from python_pydantic_response_as_param.pydantic.attack_result import AttackResult +from python_pydantic_response_as_param.pydantic.equipment import Equipment +from python_pydantic_response_as_param.pydantic.sword import Sword + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py index 4d248d886d..bc79eeadc0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py index 1b7b6978ac..f7882a1733 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py index db74c66a7b..01eed06e5b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py @@ -331,6 +331,7 @@ def attack_monster( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, @@ -403,6 +404,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi index 25f54f24ae..beb78e0ec9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi @@ -323,6 +323,7 @@ class AttackMonsterRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, @@ -395,6 +396,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py index c4174705dc..2f320a3124 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py @@ -268,6 +268,7 @@ def retrieve_equipment( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi index 54b52fff74..218f4d70e7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi @@ -260,6 +260,7 @@ class RetrieveEquipmentRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py index d5615abdb2..39919eb7d0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py index 9357ddcab6..037eb109ea 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_response_with_none_fieldvalue.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py index ec42d0c013..ed33c28886 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py index 9cfdea4032..d9ab267782 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py index f5dc3b0845..2d65714abd 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi index a311e8b805..2b2fc30930 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py index a145870f24..0f83757e65 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py index f0fa3e7f02..48fd654731 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic.pydantic.test_fetch400_response import TestFetch400Response +from python_pydantic.pydantic.test_fetch500_response import TestFetch500Response +from python_pydantic.pydantic.test_fetch_response import TestFetchResponse +from python_pydantic.pydantic.test_reserved_word import TestReservedWord + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py index 7f31a18b8d..5455050913 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py index 00289c1382..598dc72270 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py index ca01152e25..a199a6b3f2 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py @@ -266,6 +266,7 @@ def reserved_word( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi index 36de9bafb1..673298ef98 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi @@ -258,6 +258,7 @@ class ReservedWordRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py index 564babe6d3..398ab87537 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py @@ -386,6 +386,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -450,6 +451,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi index 9dce362e40..7fb824b5c0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi @@ -376,6 +376,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -440,6 +441,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py index e34fc5bf09..0cb3529888 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py index 86149d2c58..2f6075d337 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_schema_with_underscores_in_name.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py index 9ae54cb4ca..3d28077fd0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py index 2104c286ba..b6c6a31b0b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py index 1d2e78b4a4..a4e88c70c5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi index ba043cae12..e97892a10b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py index be54722be2..4d59e400e2 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py index 9158b3ef4f..2d1bd9e442 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_union.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py index 2f8d065a13..0d471af0b9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py index a6a1568d54..c71bb6f6d0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py index ab0259726c..1f28340d0c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi index 69dc4b314d..003795acdd 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py index c6707ecb40..30f2a99c1d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py index 0717a4c65a..62999be851 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py index 569224c367..f7139702c8 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py index dfa805b86d..a7339fab3d 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py index 354fa7ee11..b256b8558a 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi index a5bb4ddd20..f3f6fba438 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py index 752099dac4..28518754cd 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py index 1ea0788acb..a2274f828f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py @@ -29,6 +29,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +54,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py index b29602112c..7477a46e6a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py @@ -143,10 +143,16 @@ def __init__(self, host=None, else: self.api_key = api_key if client_id: + if type(client_id) is not str: + raise ClientConfigurationError("client_id must be a string") self.api_key['PartnerClientId'] = client_id if signature: + if type(signature) is not str: + raise ClientConfigurationError("signature must be a string") self.api_key['PartnerSignature'] = signature if timestamp: + if type(timestamp) is not str: + raise ClientConfigurationError("timestamp must be a string") self.api_key['PartnerTimestamp'] = timestamp """dict to store API key(s) """ diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py index a58bf33094..55c6bef23c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py index 0b648d0d8f..76dddf0f28 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py @@ -410,6 +410,7 @@ def list_user_accounts( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, @@ -454,6 +455,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi index d3bc2b8fa8..7dadf0f035 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi @@ -399,6 +399,7 @@ class ListUserAccounts(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, @@ -443,6 +444,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py index 399deba423..60c21df00d 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py @@ -454,6 +454,7 @@ def get_user_account_details( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, @@ -508,6 +509,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi index 4c4aa634dd..7ee5a67fd0 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi @@ -443,6 +443,7 @@ class GetUserAccountDetails(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, @@ -497,6 +498,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py index 674e0deaf1..333282a22e 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py @@ -479,6 +479,7 @@ def update_user_account( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, @@ -533,6 +534,7 @@ def put( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi index c895605ce1..f14c162952 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi @@ -468,6 +468,7 @@ class UpdateUserAccount(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ class ApiForput(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py index 7921307c29..59d9525bea 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py @@ -479,6 +479,7 @@ def get_user_account_balance( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, @@ -533,6 +534,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi index a604c5775a..b3d9edc735 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi @@ -468,6 +468,7 @@ class GetUserAccountBalance(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py index d2d2e55896..d7d9b16aef 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py @@ -489,6 +489,7 @@ def get_user_holdings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -541,6 +542,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi index 9ee0093813..4e784c03af 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi @@ -476,6 +476,7 @@ class GetUserHoldings(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -528,6 +529,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py index ea068ce8a7..f8422b88fc 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py @@ -640,6 +640,7 @@ def get_option_strategy( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, @@ -710,6 +711,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi index f6d0d96793..cc2957f8d7 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi @@ -623,6 +623,7 @@ class GetOptionStrategy(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, @@ -693,6 +694,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py index 2a21cc628b..5973dce0f6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py @@ -464,6 +464,7 @@ def get_options_strategy_quote( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, @@ -520,6 +521,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi index 1d8afd59bc..051cca3dbf 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi @@ -453,6 +453,7 @@ class GetOptionsStrategyQuote(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, @@ -509,6 +510,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py index d5be042c5f..e7641e806b 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py @@ -627,6 +627,7 @@ def place_option_strategy( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, @@ -701,6 +702,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi index fa690da672..c65b0bc356 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi @@ -616,6 +616,7 @@ class PlaceOptionStrategy(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, @@ -690,6 +691,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py index a57dfe535b..e555e5fe90 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py @@ -473,6 +473,7 @@ def list_option_holdings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -525,6 +526,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi index a425186066..54f3243f34 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi @@ -462,6 +462,7 @@ class ListOptionHoldings(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -514,6 +515,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py index 471fd80fd8..fe51a3f318 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py @@ -465,6 +465,7 @@ def get_options_chain( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, @@ -521,6 +522,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi index 5c4047150d..87c1621021 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi @@ -454,6 +454,7 @@ class GetOptionsChain(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, @@ -510,6 +511,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py index f4cdca7a28..09241b421c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py @@ -539,6 +539,7 @@ def get_user_account_orders( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, @@ -599,6 +600,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi index 3349303fbd..f68ba202f3 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi @@ -516,6 +516,7 @@ class GetUserAccountOrders(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, @@ -576,6 +577,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py index 08ac519bdb..e4ed65a52c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py @@ -581,6 +581,7 @@ def cancel_user_account_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, @@ -643,6 +644,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi index 67fad1edb9..2ca4da27b7 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi @@ -569,6 +569,7 @@ class CancelUserAccountOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, @@ -631,6 +632,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py index 5d995206ba..300fcf1cbf 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py @@ -479,6 +479,7 @@ def get_user_account_positions( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, @@ -533,6 +534,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi index 2ff9878667..491c98abb4 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi @@ -468,6 +468,7 @@ class GetUserAccountPositions(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py index 8690804add..a83e2ff894 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py @@ -481,6 +481,7 @@ def get_user_account_quotes( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, @@ -541,6 +542,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi index 7bfa0973bc..cdd69916d8 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi @@ -470,6 +470,7 @@ class GetUserAccountQuotes(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, @@ -530,6 +531,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py index 372344becf..8688be3edc 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py @@ -536,6 +536,7 @@ def symbol_search_user_account( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, @@ -600,6 +601,7 @@ def post( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi index 92181c50c3..30f2d905a3 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi @@ -525,6 +525,7 @@ class SymbolSearchUserAccount(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, @@ -589,6 +590,7 @@ class ApiForpost(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py index eada9a9b84..da2b7eb1ad 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py @@ -490,6 +490,7 @@ def get_activities( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, @@ -554,6 +555,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi index 38ad4df32a..a67307e920 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi @@ -479,6 +479,7 @@ class GetActivities(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, @@ -543,6 +544,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py index d4e9aac684..3352790ce3 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py @@ -410,6 +410,7 @@ def list_brokerage_authorizations( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, @@ -454,6 +455,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi index 9332854c03..6379eacfce 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi @@ -399,6 +399,7 @@ class ListBrokerageAuthorizations(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, @@ -443,6 +444,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py index 68ade15989..562a1f568c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py @@ -468,6 +468,7 @@ def remove_brokerage_authorization( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ def delete( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi index c107ca4ba7..419b7a7434 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi @@ -455,6 +455,7 @@ class RemoveBrokerageAuthorization(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -509,6 +510,7 @@ class ApiFordelete(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py index e7a842fc28..d484562381 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py @@ -454,6 +454,7 @@ def detail_brokerage_authorization( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -508,6 +509,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi index 0865a4dfbf..db4ff4a601 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi @@ -443,6 +443,7 @@ class DetailBrokerageAuthorization(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -497,6 +498,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py index f3f7ceb9e3..26a1f53e6c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py @@ -392,6 +392,7 @@ def list_all_brokerage_authorization_type( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, @@ -432,6 +433,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi index c0b2ba09d4..1760d83c00 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi @@ -381,6 +381,7 @@ class ListAllBrokerageAuthorizationType(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, @@ -421,6 +422,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py index b694240de9..cf8f14a6c7 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py @@ -321,6 +321,7 @@ def list_all_brokerages( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( @@ -351,6 +352,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi index aebdecfa8c..28017499b9 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi @@ -310,6 +310,7 @@ class ListAllBrokerages(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( @@ -340,6 +341,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py index ff4176eac5..535511fa95 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py @@ -321,6 +321,7 @@ def list_all_currencies( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( @@ -351,6 +352,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi index 57d9ffbc54..69b4b27f7f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi @@ -310,6 +310,7 @@ class ListAllCurrencies(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( @@ -340,6 +341,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py index 53d128ea3e..72a63dd863 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py @@ -291,6 +291,7 @@ def list_all_currencies_rates( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi index 70d02bbb3b..4930f6cdb9 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi @@ -281,6 +281,7 @@ class ListAllCurrenciesRates(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py index ff769b8e91..c72b328f35 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py @@ -335,6 +335,7 @@ def get_currency_exchange_rate_pair( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, @@ -373,6 +374,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi index c9669eb43f..8627a96fb6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi @@ -325,6 +325,7 @@ class GetCurrencyExchangeRatePair(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, @@ -363,6 +364,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py index 8a82085cc7..bcdc7ddafb 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py @@ -291,6 +291,7 @@ def get_stock_exchanges( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi index 160b533f24..bf8214b0f2 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi @@ -281,6 +281,7 @@ class GetStockExchanges(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py index 3f06b8bfd3..e5aeec4b07 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py @@ -463,6 +463,7 @@ def get_all_user_holdings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, @@ -511,6 +512,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi index dc1bd6e27f..26286392f6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi @@ -450,6 +450,7 @@ class GetAllUserHoldings(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, @@ -498,6 +499,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py index 5899af0df7..ed2773e09c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py @@ -469,6 +469,7 @@ def get_reporting_custom_range( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, @@ -535,6 +536,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi index c11b5c8d3f..9cb4f31a4b 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi @@ -458,6 +458,7 @@ class GetReportingCustomRange(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, @@ -524,6 +525,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py index 8e95974f79..64de66525f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py @@ -287,6 +287,7 @@ def check( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( @@ -317,6 +318,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi index 60fc641eab..8700f492a6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi @@ -281,6 +281,7 @@ class Check(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py index 34ce5a9753..2e47253452 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py @@ -321,6 +321,7 @@ def get_security_types( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( @@ -351,6 +352,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi index 084f978555..c418c656e9 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi @@ -310,6 +310,7 @@ class GetSecurityTypes(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( @@ -340,6 +341,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py index eb859b7ebe..44fc7ee559 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py @@ -457,6 +457,7 @@ def session_events( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, @@ -505,6 +506,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi index b0be5fa3bf..414fbb193c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi @@ -446,6 +446,7 @@ class SessionEvents(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, @@ -494,6 +495,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py index 05c2a332f8..583c0ea808 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py @@ -427,6 +427,7 @@ def delete_snap_trade_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, @@ -465,6 +466,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi index 0caa42b508..4c43aa6b26 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi @@ -413,6 +413,7 @@ class DeleteSnapTradeUser(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, @@ -451,6 +452,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py index 8c06f85dfc..74361d3273 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py @@ -444,6 +444,7 @@ def get_user_jwt( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, @@ -486,6 +487,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi index 617f19ba7f..56f84f26ee 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi @@ -430,6 +430,7 @@ class GetUserJwt(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, @@ -472,6 +473,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py index 3f24990182..5145def886 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py @@ -338,6 +338,7 @@ def list_snap_trade_users( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( @@ -366,6 +367,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi index ff73f34e64..55e58aec25 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi @@ -325,6 +325,7 @@ class ListSnapTradeUsers(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( @@ -353,6 +354,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py index a3bd6c22e1..c24ef1fe23 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py @@ -569,6 +569,7 @@ def login_snap_trade_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, @@ -641,6 +642,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi index 41438e46c4..83790bfac8 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi @@ -555,6 +555,7 @@ class LoginSnapTradeUser(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, @@ -627,6 +628,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py index 11c20ab133..e49476758f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py @@ -355,6 +355,7 @@ def get_partner_info( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( @@ -383,6 +384,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi index 9195cbd84e..a025a5bc12 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi @@ -341,6 +341,7 @@ class GetPartnerInfo(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( @@ -369,6 +370,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py index fb20b97bc6..8a7abb9921 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py @@ -400,6 +400,7 @@ def register_snap_trade_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, @@ -438,6 +439,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi index 49e0d1cd82..5d2c971bea 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi @@ -387,6 +387,7 @@ class RegisterSnapTradeUser(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, @@ -425,6 +426,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py index 4ab77a7aab..74c221f916 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py @@ -404,6 +404,7 @@ def reset_snap_trade_user_secret( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, @@ -446,6 +447,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi index 3540df10bf..23a17b2d45 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi @@ -391,6 +391,7 @@ class ResetSnapTradeUserSecret(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, @@ -433,6 +434,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py index 73e2b2155d..89f0ca74fe 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py @@ -378,6 +378,7 @@ def get_symbols( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, @@ -418,6 +419,7 @@ def post( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi index 0c844d5942..d9879b539d 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi @@ -367,6 +367,7 @@ class GetSymbols(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, @@ -407,6 +408,7 @@ class ApiForpost(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py index 7194a0eaa4..e36e331d32 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py @@ -382,6 +382,7 @@ def get_symbols_by_ticker( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, @@ -422,6 +423,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi index d25e365516..274050966a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi @@ -370,6 +370,7 @@ class GetSymbolsByTicker(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, @@ -410,6 +411,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py index 5a1f02f5ea..aa52ea879b 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py @@ -544,6 +544,7 @@ def get_order_impact( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, @@ -628,6 +629,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi index 2ddd5d5c7f..884840aff6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi @@ -531,6 +531,7 @@ class GetOrderImpact(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, @@ -615,6 +616,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py index b9871c0104..18d1e9f861 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py @@ -523,6 +523,7 @@ def place_oco_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, @@ -581,6 +582,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi index d3045a0b1d..630d6d237d 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi @@ -511,6 +511,7 @@ class PlaceOcoOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, @@ -569,6 +570,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py index a4a066b992..bc75b6b965 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py @@ -544,6 +544,7 @@ def place_force_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, @@ -628,6 +629,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi index 1e3855ec07..90fb250d6d 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi @@ -531,6 +531,7 @@ class PlaceForceOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, @@ -615,6 +616,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py index fefbe6b3e8..236ab24f4f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py @@ -522,6 +522,7 @@ def place_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, @@ -584,6 +585,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi index 2de573ff07..b9a5370427 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi @@ -510,6 +510,7 @@ class PlaceOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, @@ -572,6 +573,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py index d658ccbe0c..def947e9af 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1841,7 +1875,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1876,7 +1910,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1992,6 +2026,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2054,39 +2089,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py index c2df6ce8ac..5ada8ea002 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py @@ -30,6 +30,7 @@ class RequiredOptionsSymbol(TypedDict): underlying_symbol: UnderlyingSymbol + class OptionalOptionsSymbol(TypedDict, total=False): is_mini_option: bool diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py index 4f456d0733..7a21a1665e 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py @@ -30,6 +30,7 @@ class RequiredOptionsSymbolNullable(TypedDict): underlying_symbol: UnderlyingSymbol + class OptionalOptionsSymbolNullable(TypedDict, total=False): is_mini_option: bool diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py index 44e227789c..3344d93ab4 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py @@ -32,6 +32,7 @@ class RequiredUniversalSymbol(TypedDict): currencies: typing.List[Currency] + class OptionalUniversalSymbol(TypedDict, total=False): description: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py index 764db1cde9..c27d519b8c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py @@ -32,6 +32,7 @@ class RequiredUniversalSymbolNullable(TypedDict): currencies: typing.List[Currency] + class OptionalUniversalSymbolNullable(TypedDict, total=False): description: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py index a23268d27d..7af42cfcdd 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py @@ -29,6 +29,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +54,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py index 77d8736fdc..3cab8a2456 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py index 15b336ec53..af3cdb331d 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py index 6c08f98929..735cf155b9 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py @@ -380,6 +380,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -414,6 +415,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi index cc02c87414..c5441fbdf9 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi @@ -370,6 +370,7 @@ class Fetch(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -404,6 +405,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py index 4efcf40f73..ebd5543a33 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1841,7 +1875,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1876,7 +1910,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1992,6 +2026,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2054,39 +2089,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py index bfb50f902d..15ffcae45e 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_union_string_discriminator.pydantic.a import A +from python_union_string_discriminator.pydantic.b import B +from python_union_string_discriminator.pydantic.generic_schema import GenericSchema +from python_union_string_discriminator.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py index 9b6837a1fe..1916941044 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py index 2bfa29b925..29cf1e0053 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py index cac26566fd..16a5eadded 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi index c464917e39..e8ae46d6bc 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py index 9b8a004226..bd22a2b774 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py index 25ac92962a..4e2fea3716 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py @@ -28,6 +28,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -51,6 +53,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py index e38e910f3c..20e26faa75 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py @@ -97,48 +97,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -189,3 +147,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py index 61a116c3db..ed2d15f2d7 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py @@ -664,6 +664,7 @@ def post2( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, @@ -748,6 +749,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi index 47add1c665..e2fb41976f 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi @@ -642,6 +642,7 @@ class Post2(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, @@ -726,6 +727,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py index 4fc8e9792b..c3ba1aa532 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py @@ -539,6 +539,7 @@ def check_eligibility( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -591,6 +592,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi index 204ed1d028..83e158ab55 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi @@ -527,6 +527,7 @@ class CheckEligibility(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -579,6 +580,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py index 15d1938b18..d3a066dc87 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py @@ -658,6 +658,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -738,6 +739,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi index 80d167ca62..497747d88b 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi @@ -636,6 +636,7 @@ class Post(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -716,6 +717,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py index 0655d6e7a6..fec824113b 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py @@ -519,6 +519,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -563,6 +564,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi index 60237cc865..72a1ef3fc5 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi @@ -507,6 +507,7 @@ class Get(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -551,6 +552,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py index c03e534e9c..46dc57292c 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py @@ -519,6 +519,7 @@ def cancel( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -563,6 +564,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi index 1ce95f6e7e..cc9ccf2fb0 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi @@ -507,6 +507,7 @@ class Cancel(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -551,6 +552,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py index 5ebd10d147..ecdb5de655 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py @@ -594,6 +594,7 @@ def refund( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, @@ -648,6 +649,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi index da01ecdfe8..90ce5d4245 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi @@ -582,6 +582,7 @@ class Refund(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, @@ -636,6 +637,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py index 20322f4aaf..802da470af 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py @@ -606,6 +606,7 @@ def update_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -668,6 +669,7 @@ def put( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi index f0a950c82c..91442e6035 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi @@ -594,6 +594,7 @@ class UpdateOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -656,6 +657,7 @@ class ApiForput(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py index c6381db7c4..82d197e6b1 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py @@ -519,6 +519,7 @@ def verify_authorization( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -563,6 +564,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi index 4fd2d0408f..3882bfa92b 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi @@ -507,6 +507,7 @@ class VerifyAuthorization(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -551,6 +552,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py index 699e7a9c33..edbf6165a7 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py @@ -581,6 +581,7 @@ def search( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -633,6 +634,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi index 68e4688730..422116e698 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi @@ -569,6 +569,7 @@ class Search(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -621,6 +622,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py index b2768e1bc0..0b8abcb34c 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py @@ -550,6 +550,7 @@ def update_order2( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -612,6 +613,7 @@ def put( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi index 080a93caea..796988af72 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi @@ -538,6 +538,7 @@ class UpdateOrder2(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -600,6 +601,7 @@ class ApiForput(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py index 9bc08428b3..dfaebfb865 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py @@ -974,6 +974,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1840,7 +1874,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1875,7 +1909,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1991,6 +2025,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2053,39 +2088,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py index b71033e8e3..6c79d769ee 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py @@ -20,6 +20,7 @@ class RequiredAuthorizationModel(TypedDict): Status: GwAuthorizationStatus + class OptionalAuthorizationModel(TypedDict, total=False): Date: datetime diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py index a1edac2ddd..54d02b6deb 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py @@ -23,6 +23,7 @@ class RequiredInitiatePlanResponse(TypedDict): Status: PlanStatus + class OptionalInitiatePlanResponse(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py index e068404231..35c73b50bc 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py @@ -23,6 +23,7 @@ class RequiredInstallment(TypedDict): Status: InstallmentStatus + class OptionalInstallment(TypedDict, total=False): ProcessDateTime: datetime diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py index ebee037d66..70d8c2483e 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py @@ -27,6 +27,7 @@ class RequiredInstallmentPlanCreateRequest(TypedDict): TermsAndConditionsAccepted: bool + class OptionalInstallmentPlanCreateRequest(TypedDict, total=False): Attempt3dSecure: bool diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py index 8be76305f9..6c3dfc90d8 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py @@ -29,6 +29,7 @@ class RequiredInstallmentPlanCreateResponse(TypedDict): Status: PlanStatus + class OptionalInstallmentPlanCreateResponse(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py index 41225ce586..29be76d14c 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py @@ -30,6 +30,7 @@ class RequiredInstallmentPlanGetResponse(TypedDict): Status: PlanStatus + class OptionalInstallmentPlanGetResponse(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py index ed08fe2d48..70c4febf3a 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py @@ -25,6 +25,7 @@ class RequiredInstallmentPlanInitiateRequest(TypedDict): AutoCapture: bool + class OptionalInstallmentPlanInitiateRequest(TypedDict, total=False): Attempt3dSecure: bool diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py index 2dbc0e62f1..7d432a371b 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py @@ -19,6 +19,7 @@ class RequiredInstallmentPlanRefundRequest(TypedDict): Amount: typing.Union[int, float] + class OptionalInstallmentPlanRefundRequest(TypedDict, total=False): RefundStrategy: RefundStrategy diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py index 9665daa42b..80b28af5f1 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py @@ -22,6 +22,7 @@ class RequiredInstallmentPlanUpdateResponse(TypedDict): ShippingStatus: ShippingStatus + class OptionalInstallmentPlanUpdateResponse(TypedDict, total=False): RefOrderNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py index efac890146..99068b2ffd 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py @@ -23,6 +23,7 @@ class RequiredPaymentMethodModel(TypedDict): Type: PaymentMethodType + class OptionalPaymentMethodModel(TypedDict, total=False): Card: CardData diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py index fcd5929824..4e7790ae85 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py @@ -25,6 +25,7 @@ class RequiredPaymentPlanOptionModel(TypedDict): LastInstallmentAmount: typing.Union[int, float] + class OptionalPaymentPlanOptionModel(TypedDict, total=False): Links: LinksModel diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py index b207fd1833..d875909343 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py @@ -26,6 +26,7 @@ class RequiredPlanData(TypedDict): PurchaseMethod: PurchaseMethod + class OptionalPlanData(TypedDict, total=False): TerminalId: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py index 70c9ce6f2a..a4ea9fe79a 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py @@ -22,6 +22,7 @@ class RequiredPlanDataModel(TypedDict): PurchaseMethod: PurchaseMethod + class OptionalPlanDataModel(TypedDict, total=False): Currency: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py index 6482cf95cc..6d226ca95f 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py @@ -27,6 +27,7 @@ class RequiredRefundModel(TypedDict): CreditRefundAmount: typing.Union[int, float] + class OptionalRefundModel(TypedDict, total=False): RefundId: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py index 70f685c3e2..2f792bf900 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py @@ -30,6 +30,7 @@ class RequiredSearchInstallmentPlanResponseItem(TypedDict): Status: PlanStatus + class OptionalSearchInstallmentPlanResponseItem(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py index cb2c9a6715..ebcc465533 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py @@ -19,6 +19,7 @@ class RequiredVerifyAuthorizationResponse(TypedDict): IsAuthorized: bool + class OptionalVerifyAuthorizationResponse(TypedDict, total=False): AuthorizationAmount: typing.Union[int, float]