diff --git a/languages/python/templates/__init__package.mustache b/languages/python/templates/__init__package.mustache index 6f1bdfd..0d79457 100644 --- a/languages/python/templates/__init__package.mustache +++ b/languages/python/templates/__init__package.mustache @@ -1,4 +1,4 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/__init__package.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/__init__package.mustache for the original template }} # coding: utf-8 # flake8: noqa diff --git a/languages/python/templates/api.mustache b/languages/python/templates/api.mustache index 939a8a6..43bf350 100644 --- a/languages/python/templates/api.mustache +++ b/languages/python/templates/api.mustache @@ -1,7 +1,8 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/api.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/api.mustache for the original template }} # coding: utf-8 {{>partial_header}} + import warnings from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt from typing import Any, Dict, List, Optional, Tuple, Union diff --git a/languages/python/templates/api_client.mustache b/languages/python/templates/api_client.mustache index cc1f748..3ec1946 100644 --- a/languages/python/templates/api_client.mustache +++ b/languages/python/templates/api_client.mustache @@ -1,8 +1,9 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/api_client.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/api_client.mustache for the original template }} # coding: utf-8 {{>partial_header}} + import datetime from dateutil.parser import parse from enum import Enum @@ -66,6 +67,7 @@ class ApiClient: 'date': datetime.date, 'datetime': datetime.datetime, 'decimal': decimal.Decimal, + 'UUID': uuid.UUID, 'object': object, } _pool = None @@ -320,7 +322,7 @@ class ApiClient: response_text = None return_data = None try: - if response_type == "bytearray": + if response_type in ("bytearray", "bytes"): return_data = response_data.data elif response_type == "file": return_data = self.__deserialize_file(response_data) @@ -385,28 +387,24 @@ class ApiClient: return obj.isoformat() elif isinstance(obj, decimal.Decimal): return str(obj) - elif isinstance(obj, dict): - obj_dict = obj + return { + key: self.sanitize_for_serialization(val) + for key, val in obj.items() + } + + # Convert model obj to dict except + # attributes `openapi_types`, `attribute_map` + # and attributes which value is not None. + # Convert attribute name to json key in + # model definition for request. + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() else: - # Convert model obj to dict except - # attributes `openapi_types`, `attribute_map` - # and attributes which value is not None. - # Convert attribute name to json key in - # model definition for request. - if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): # noqa: B009 - obj_dict = obj.to_dict() - else: - obj_dict = obj.__dict__ + obj_dict = obj.__dict__ - if isinstance(obj_dict, list): - # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() # noqa: E501 - return self.sanitize_for_serialization(obj_dict) + return self.sanitize_for_serialization(obj_dict) - return { - key: self.sanitize_for_serialization(val) - for key, val in obj_dict.items() - } def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. @@ -488,6 +486,8 @@ class ApiClient: return self.__deserialize_datetime(data) elif klass is decimal.Decimal: return decimal.Decimal(data) + elif klass is uuid.UUID: + return uuid.UUID(data) elif issubclass(klass, Enum): return self.__deserialize_enum(data, klass) else: diff --git a/languages/python/templates/exceptions.mustache b/languages/python/templates/exceptions.mustache index 4ef2293..1594a2d 100644 --- a/languages/python/templates/exceptions.mustache +++ b/languages/python/templates/exceptions.mustache @@ -1,4 +1,4 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/exceptions.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/exceptions.mustache for the original template }} # coding: utf-8 {{>partial_header}} @@ -96,9 +96,9 @@ class ApiKeyError(OpenApiException, KeyError): class ApiException(OpenApiException): def __init__( - self, - status=None, - reason=None, + self, + status=None, + reason=None, http_resp=None, *, body: Optional[str] = None, @@ -124,10 +124,10 @@ class ApiException(OpenApiException): @classmethod def from_response( - cls, - *, - http_resp, - body: Optional[str], + cls, + *, + http_resp, + body: Optional[str], data: Optional[Any], ) -> Self: if http_resp.status == 400: diff --git a/languages/python/templates/model_generic.mustache b/languages/python/templates/model_generic.mustache index 2508acb..b334b0c 100644 --- a/languages/python/templates/model_generic.mustache +++ b/languages/python/templates/model_generic.mustache @@ -1,4 +1,4 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/model_generic.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/model_generic.mustache for the original template }} from __future__ import annotations import pprint import re # noqa: F401 @@ -15,6 +15,7 @@ from pydantic import field_validator {{! TEMPLATE CUSTOMIZATION - END - import for workaround below }} from typing import Optional, Set from typing_extensions import Self +from pydantic_core import to_jsonable_python {{#hasChildren}} {{#discriminator}} @@ -56,6 +57,9 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/isNullable}} {{/required}} + if not isinstance(value, str): + value = str(value) + if not re.match(r"{{{.}}}", value{{#vendorExtensions.x-modifiers}} ,re.{{{.}}}{{/vendorExtensions.x-modifiers}}): raise ValueError(r"must validate the regular expression {{{vendorExtensions.x-pattern}}}") return value @@ -114,7 +118,8 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/vars}} model_config = ConfigDict( - populate_by_name=True, + validate_by_name=True, + validate_by_alias=True, validate_assignment=True, protected_namespaces=(), ) @@ -147,8 +152,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} def to_json(self) -> str: """Returns the JSON representation of the model using alias""" - # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead - return json.dumps(self.to_dict()) + return json.dumps(to_jsonable_python(self.to_dict())) @classmethod def from_json(cls, json_str: str) -> Optional[{{^hasChildren}}Self{{/hasChildren}}{{#hasChildren}}{{#discriminator}}Union[{{#mappedModels}}{{{modelName}}}{{^-last}}, {{/-last}}{{/mappedModels}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}{{/hasChildren}}]: @@ -201,7 +205,21 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} _dict['{{{baseName}}}'] = _items {{/items.items.isPrimitiveType}} {{/items.isArray}} + {{#items.isMap}} + {{^items.items.isPrimitiveType}} + # override the default output from pydantic by calling `to_dict()` of each item in {{{name}}} (list of dict) + _items = [] + if self.{{{name}}}: + for _item_{{{name}}} in self.{{{name}}}: + if _item_{{{name}}}: + _items.append( + {_inner_key: _inner_value.to_dict() for _inner_key, _inner_value in _item_{{{name}}}.items()} + ) + _dict['{{{baseName}}}'] = _items + {{/items.items.isPrimitiveType}} + {{/items.isMap}} {{^items.isArray}} + {{^items.isMap}} {{^items.isPrimitiveType}} {{^items.isEnumOrRef}} # override the default output from pydantic by calling `to_dict()` of each item in {{{name}}} (list) @@ -213,6 +231,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} _dict['{{{baseName}}}'] = _items {{/items.isEnumOrRef}} {{/items.isPrimitiveType}} + {{/items.isMap}} {{/items.isArray}} {{/isArray}} {{#isMap}} @@ -229,6 +248,20 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} _dict['{{{baseName}}}'] = _field_dict_of_array {{/items.items.isPrimitiveType}} {{/items.isArray}} + {{#items.isMap}} + {{^items.items.isPrimitiveType}} + # override the default output from pydantic by calling `to_dict()` of each value in {{{name}}} (dict of dict) + _field_dict_of_dict = {} + if self.{{{name}}}: + for _key_{{{name}}}, _value_{{{name}}} in self.{{{name}}}.items(): + if _value_{{{name}}} is not None: + _field_dict_of_dict[_key_{{{name}}}] = { + _key: _value.to_dict() for _key, _value in _value_{{{name}}}.items() + } + _dict['{{{baseName}}}'] = _field_dict_of_dict + {{/items.items.isPrimitiveType}} + {{/items.isMap}} + {{^items.isMap}} {{^items.isArray}} {{^items.isPrimitiveType}} {{^items.isEnumOrRef}} @@ -242,6 +275,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/items.isEnumOrRef}} {{/items.isPrimitiveType}} {{/items.isArray}} + {{/items.isMap}} {{/isMap}} {{/isContainer}} {{^isContainer}} @@ -312,6 +346,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{#allVars}} {{#isContainer}} {{#isArray}} + {{#items.isContainer}} {{#items.isArray}} {{#items.items.isPrimitiveType}} "{{{baseName}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}} @@ -323,7 +358,19 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} ] if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} {{/items.items.isPrimitiveType}} {{/items.isArray}} - {{^items.isArray}} + {{#items.isMap}} + {{#items.items.isPrimitiveType}} + "{{{baseName}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}} + {{/items.items.isPrimitiveType}} + {{^items.items.isPrimitiveType}} + "{{{baseName}}}": [ + {_inner_key: {{{items.items.dataType}}}.from_dict(_inner_value) for _inner_key, _inner_value in _item.items()} + for _item in obj["{{{baseName}}}"] + ] if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} + {{/items.items.isPrimitiveType}} + {{/items.isMap}} + {{/items.isContainer}} + {{^items.isContainer}} {{^items.isPrimitiveType}} {{#items.isEnumOrRef}} "{{{baseName}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}} @@ -335,7 +382,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{#items.isPrimitiveType}} "{{{baseName}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}} {{/items.isPrimitiveType}} - {{/items.isArray}} + {{/items.isContainer}} {{/isArray}} {{#isMap}} {{^items.isPrimitiveType}} @@ -350,20 +397,18 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} if _v is not None else None ) - for _k, _v in obj.get("{{{baseName}}}").items() + for _k, _v in obj["{{{baseName}}}"].items() ) if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} {{/items.isMap}} {{#items.isArray}} - "{{{baseName}}}": dict( - (_k, - [{{{items.items.dataType}}}.from_dict(_item) for _item in _v] - if _v is not None - else None - ) - for _k, _v in obj.get("{{{baseName}}}", {}).items() - ){{^-last}},{{/-last}} + "{{{baseName}}}": { + _k: [{{{items.items.dataType}}}.from_dict(_item) for _item in _v] if _v is not None else None + for _k, _v in obj["{{{baseName}}}"].items() + } + if obj.get("{{{baseName}}}") is not None + else None{{^-last}},{{/-last}} {{/items.isArray}} {{/items.isContainer}} {{^items.isContainer}} diff --git a/languages/python/templates/model_oneof.mustache b/languages/python/templates/model_oneof.mustache index d71027b..4fe2206 100644 --- a/languages/python/templates/model_oneof.mustache +++ b/languages/python/templates/model_oneof.mustache @@ -1,4 +1,4 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/model_oneof.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/model_oneof.mustache for the original template }} from __future__ import annotations import json import pprint diff --git a/languages/python/templates/rest.mustache b/languages/python/templates/rest.mustache index 8637554..4314300 100644 --- a/languages/python/templates/rest.mustache +++ b/languages/python/templates/rest.mustache @@ -1,11 +1,13 @@ -{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.20.0/modules/openapi-generator/src/main/resources/python/rest.mustache for the original template }} +{{! This template was customized. See https://github.com/OpenAPITools/openapi-generator/blob/v7.22.0/modules/openapi-generator/src/main/resources/python/rest.mustache for the original template }} # coding: utf-8 {{>partial_header}} + import io import json import re +import ssl {{! TEMPLATE CUSTOMIZATION - BEGIN - requests instead of urllib3 }} import requests diff --git a/scripts/generate-sdk/generate-sdk.sh b/scripts/generate-sdk/generate-sdk.sh index 55244a6..1764f0c 100755 --- a/scripts/generate-sdk/generate-sdk.sh +++ b/scripts/generate-sdk/generate-sdk.sh @@ -61,7 +61,7 @@ go) python) # When the GENERATOR_VERSION changes, migrate also the templates in templates/python # Renovate: datasource=github-tags depName=OpenAPITools/openapi-generator versioning=semver - GENERATOR_VERSION="v7.20.0" + GENERATOR_VERSION="v7.22.0" ;; java) # When the GENERATOR_VERSION changes, migrate also the templates in templates/java