From c62a19e0dda4416fef60f07330c54f8b2c720f37 Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 18 Aug 2026 12:47:58 -0700 Subject: [PATCH] Share Python legacy model helpers --- .../codegen/CodegenConstants.java | 1 + .../codegen/DefaultGenerator.java | 1 + .../languages/PythonClientCodegen.java | 29 +++++++ .../python/_legacy_model_helpers.mustache | 5 ++ .../main/resources/python/api_client.mustache | 5 ++ .../resources/python/model_anyof.mustache | 10 +++ .../resources/python/model_generic.mustache | 10 +++ .../resources/python/model_oneof.mustache | 10 +++ .../python/PythonClientCodegenTest.java | 33 ++++++-- .../.openapi-generator/FILES | 1 + .../_legacy_model_helpers.py | 80 +++++++++++++++++++ .../legacy_model_dict_client/api_client.py | 29 +------ .../models/additional_properties_model.py | 72 ++--------------- .../models/any_of_model.py | 72 ++--------------- .../models/legacy_base.py | 72 ++--------------- .../models/legacy_model.py | 72 ++--------------- .../models/nested_model.py | 72 ++--------------- .../models/one_of_model.py | 72 ++--------------- 18 files changed, 215 insertions(+), 431 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/python/_legacy_model_helpers.mustache create mode 100644 samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/_legacy_model_helpers.py diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java index 03faf2e32189..8e574e348bf6 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java @@ -340,6 +340,7 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, // Not user-configurable. System provided for use in templates. public static final String GENERATE_MODELS = "generateModels"; public static final String GENERATE_MODEL_DOCS = "generateModelDocs"; + public static final String GENERATE_SUPPORTING_FILES = "generateSupportingFiles"; public static final String VIRTUAL_SERVICE = "virtualService"; public static final String VIRTUAL_SERVICE_DESC = "Generate Spring boot rest service as virtual service with Virtualan"; diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java index 6636187fec0a..3f0d7331c53b 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java @@ -234,6 +234,7 @@ void configureGeneratorProperties() { config.additionalProperties().put(CodegenConstants.GENERATE_APIS, generateApis); config.additionalProperties().put(CodegenConstants.GENERATE_MODELS, generateModels); + config.additionalProperties().put(CodegenConstants.GENERATE_SUPPORTING_FILES, generateSupportingFiles); config.additionalProperties().put(CodegenConstants.GENERATE_WEBHOOKS, generateWebhooks); config.additionalProperties().put(CodegenConstants.GENERATE_RECURSIVE_DEPENDENT_MODELS, generateRecursiveDependentModels); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java index 17126df6a525..7725090a5df7 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java @@ -22,6 +22,7 @@ import lombok.Setter; import org.apache.commons.lang3.Strings; import org.openapitools.codegen.*; +import org.openapitools.codegen.config.GlobalSettings; import org.openapitools.codegen.meta.GeneratorMetadata; import org.openapitools.codegen.meta.Stability; import org.openapitools.codegen.meta.features.*; @@ -65,6 +66,8 @@ public class PythonClientCodegen extends AbstractPythonCodegen implements Codege public static final String BUILD_SYSTEM = "buildSystem"; public static final String SUPPORT_HTTPX_SYNC = "supportHttpxSync"; public static final String USE_INDEPENDENT_IMPLICIT_CLIENTS = "useIndependentImplicitClients"; + private static final String USE_LEGACY_MODEL_HELPERS_MODULE = "useLegacyModelHelpersModule"; + private static final String LEGACY_MODEL_HELPERS_FILE = "_legacy_model_helpers.py"; private static final Set SYNC_API_LIFECYCLE_METHODS = Set.of("close", "__enter__", "__exit__"); private static final Set ASYNC_API_LIFECYCLE_METHODS = @@ -391,6 +394,14 @@ public void processOpts() { String modelPath = packagePath() + File.separatorChar + modelPackage.replace('.', File.separatorChar); String apiPath = packagePath() + File.separatorChar + apiPackage.replace('.', File.separatorChar); + if (compatibleWithPythonLegacy && generatesLegacyModelHelpersModule()) { + additionalProperties.put(USE_LEGACY_MODEL_HELPERS_MODULE, true); + supportingFiles.add(new SupportingFile( + "_legacy_model_helpers.mustache", packagePath(), LEGACY_MODEL_HELPERS_FILE)); + } else { + additionalProperties.remove(USE_LEGACY_MODEL_HELPERS_MODULE); + } + String readmePath = "README.md"; String readmeTemplate = "README.mustache"; if (generateSourceCodeOnly) { @@ -659,6 +670,24 @@ private boolean usesLegacyApiCompatibility() { return compatibleWithPythonLegacy && DEFAULT_LIBRARY.equals(getLibrary()); } + private boolean generatesLegacyModelHelpersModule() { + if (!Boolean.TRUE.equals(additionalProperties.get(CodegenConstants.GENERATE_SUPPORTING_FILES))) { + return false; + } + + String requestedSupportingFiles = GlobalSettings.getProperty(CodegenConstants.SUPPORTING_FILES); + if (requestedSupportingFiles == null || requestedSupportingFiles.isBlank()) { + return true; + } + + for (String requestedFile : requestedSupportingFiles.split(",")) { + if (LEGACY_MODEL_HELPERS_FILE.equals(requestedFile.trim())) { + return true; + } + } + return false; + } + private boolean supportsHttpxSync() { return "httpx".equals(getLibrary()) && Boolean.parseBoolean(String.valueOf( diff --git a/modules/openapi-generator/src/main/resources/python/_legacy_model_helpers.mustache b/modules/openapi-generator/src/main/resources/python/_legacy_model_helpers.mustache new file mode 100644 index 000000000000..02a518ab589a --- /dev/null +++ b/modules/openapi-generator/src/main/resources/python/_legacy_model_helpers.mustache @@ -0,0 +1,5 @@ +{{>partial_header}} + +from typing import Any + +{{>_legacy_model_dict_helpers}} diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index 874d9cd3efef..ba219065c1b0 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -39,7 +39,12 @@ from {{packageName}}.exceptions import ( {{#compatibleWithPythonLegacy}} +{{#useLegacyModelHelpersModule}} +from {{packageName}}._legacy_model_helpers import _get_openapi_to_dict +{{/useLegacyModelHelpersModule}} +{{^useLegacyModelHelpersModule}} {{>_legacy_model_identity}} +{{/useLegacyModelHelpersModule}} {{/compatibleWithPythonLegacy}} diff --git a/modules/openapi-generator/src/main/resources/python/model_anyof.mustache b/modules/openapi-generator/src/main/resources/python/model_anyof.mustache index 7a7f52f755a0..ff77f479f37a 100644 --- a/modules/openapi-generator/src/main/resources/python/model_anyof.mustache +++ b/modules/openapi-generator/src/main/resources/python/model_anyof.mustache @@ -16,7 +16,17 @@ from pydantic import Field from pydantic_core import to_jsonable_python +{{#useLegacyModelHelpersModule}} +from {{packageName}}._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) +{{/useLegacyModelHelpersModule}} +{{^useLegacyModelHelpersModule}} {{>_legacy_model_dict_helpers}} +{{/useLegacyModelHelpersModule}} {{/compatibleWithPythonLegacy}} diff --git a/modules/openapi-generator/src/main/resources/python/model_generic.mustache b/modules/openapi-generator/src/main/resources/python/model_generic.mustache index 3d1758ac7ec6..4f6139d16a85 100644 --- a/modules/openapi-generator/src/main/resources/python/model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/python/model_generic.mustache @@ -35,7 +35,17 @@ if TYPE_CHECKING: {{/hasChildren}} {{#compatibleWithPythonLegacy}} +{{#useLegacyModelHelpersModule}} +from {{packageName}}._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) +{{/useLegacyModelHelpersModule}} +{{^useLegacyModelHelpersModule}} {{>_legacy_model_dict_helpers}} +{{/useLegacyModelHelpersModule}} {{/compatibleWithPythonLegacy}} diff --git a/modules/openapi-generator/src/main/resources/python/model_oneof.mustache b/modules/openapi-generator/src/main/resources/python/model_oneof.mustache index 8365ae0bb61f..696d3ff4be6f 100644 --- a/modules/openapi-generator/src/main/resources/python/model_oneof.mustache +++ b/modules/openapi-generator/src/main/resources/python/model_oneof.mustache @@ -14,7 +14,17 @@ from typing_extensions import Literal, Self from pydantic_core import to_jsonable_python +{{#useLegacyModelHelpersModule}} +from {{packageName}}._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) +{{/useLegacyModelHelpersModule}} +{{^useLegacyModelHelpersModule}} {{>_legacy_model_dict_helpers}} +{{/useLegacyModelHelpersModule}} {{/compatibleWithPythonLegacy}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java index 6b9c96417782..90963fb17da1 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java @@ -974,6 +974,8 @@ public void testLegacyModelToDictRendering() throws IOException { defaultOutputPath + "openapi_client/api/default_api.py"); final Path defaultApiClient = Paths.get( defaultOutputPath + "openapi_client/api_client.py"); + final Path defaultLegacyHelpers = Paths.get( + defaultOutputPath + "openapi_client/_legacy_model_helpers.py"); assertFileContains(defaultModel, "return json.dumps(to_jsonable_python(self.to_dict()))", @@ -997,6 +999,7 @@ public void testLegacyModelToDictRendering() throws IOException { "async_req", " _preload_content: bool = True", "return self.api_client.pool.apply_async("); TestUtils.assertFileNotContains(defaultApiClient, "_OPENAPI_GENERATOR_TO_DICT"); + Assert.assertFalse(Files.exists(defaultLegacyHelpers)); final PythonClientCodegen codegen = new PythonClientCodegen(); codegen.additionalProperties().put( @@ -1010,12 +1013,12 @@ public void testLegacyModelToDictRendering() throws IOException { final Path api = Paths.get( outputPath + "openapi_client/api/default_api.py"); final Path apiClient = Paths.get(outputPath + "openapi_client/api_client.py"); + final Path legacyHelpers = Paths.get( + outputPath + "openapi_client/_legacy_model_helpers.py"); assertFileContains(model, - "def _get_openapi_to_dict(value: Any) -> Any:", - "def _to_legacy_item(value: Any, serialize: bool) -> Any:", - "def _to_legacy_value(value: Any, serialize: bool) -> Any:", - "def _to_openapi_value(value: Any) -> Any:", + "from openapi_client._legacy_model_helpers import (", + " _OPENAPI_GENERATOR_TO_DICT,", "def to_dict(self, serialize: bool = False) -> Dict[str, Any]:", "_to_legacy_value(getattr(self, \"renamed\", None), serialize)", "def __openapi_generator_modern_projection(self) -> Dict[str, Any]:", @@ -1033,6 +1036,10 @@ public void testLegacyModelToDictRendering() throws IOException { "def __eq__(self, other: object) -> bool:", "def __ne__(self, other: object) -> bool:"); TestUtils.assertFileNotContains(model, + "def _get_openapi_to_dict(value: Any) -> Any:", + "def _to_legacy_item(value: Any, serialize: bool) -> Any:", + "def _to_legacy_value(value: Any, serialize: bool) -> Any:", + "def _to_openapi_value(value: Any) -> Any:", "_legacy_model_to_dict_impl: ClassVar", "def _to_openapi_dict("); assertFileContains(nestedModel, "camel_case: Optional[StrictStr]", @@ -1045,16 +1052,21 @@ public void testLegacyModelToDictRendering() throws IOException { for (String wrapper : Arrays.asList("one_of_model.py", "any_of_model.py")) { final Path wrapperModel = Paths.get(outputPath + "openapi_client/models/" + wrapper); assertFileContains(wrapperModel, + "from openapi_client._legacy_model_helpers import (", "def to_dict(self, serialize: bool = False) -> Any:", "def __openapi_generator_modern_projection(self) -> Any:", "del __openapi_generator_modern_projection"); TestUtils.assertFileNotContains(wrapperModel, + "def _get_openapi_to_dict(value: Any) -> Any:", + "def _to_legacy_item(value: Any, serialize: bool) -> Any:", + "def _to_legacy_value(value: Any, serialize: bool) -> Any:", + "def _to_openapi_value(value: Any) -> Any:", "_legacy_model_to_dict_impl: ClassVar", "def _to_openapi_dict(", "openapi_types", "attribute_map", "extra=\"forbid\"", "def __repr__", "def __eq__"); } assertFileContains(apiClient, - "def _get_openapi_to_dict(value: Any) -> Any:", + "from openapi_client._legacy_model_helpers import _get_openapi_to_dict", "to_dict = getattr(obj, 'to_dict', None)", "to_openapi_dict = _get_openapi_to_dict(obj)", "if to_openapi_dict is not None:", @@ -1071,6 +1083,13 @@ public void testLegacyModelToDictRendering() throws IOException { "response_types_map: Dict[str, Optional[str]]", "return self._get_pool().apply_async(call)", "response_data.getheaders()"); + TestUtils.assertFileNotContains(apiClient, + "def _get_openapi_to_dict(value: Any) -> Any:"); + assertFileContains(legacyHelpers, + "def _get_openapi_to_dict(value: Any) -> Any:", + "def _to_legacy_item(value: Any, serialize: bool) -> Any:", + "def _to_legacy_value(value: Any, serialize: bool) -> Any:", + "def _to_openapi_value(value: Any) -> Any:"); assertFileContains(api, "async_req: Optional[bool] = None", "_preload_content: bool = True", @@ -1169,9 +1188,9 @@ public void testLegacyModelToDictSupportsModelOnlyGeneration() throws IOExceptio "def _to_legacy_item(value: Any, serialize: bool) -> Any:", "def _to_legacy_value(value: Any, serialize: bool) -> Any:", "def _to_openapi_value(value: Any) -> Any:"); - TestUtils.assertFileNotContains(model, "_legacy_model_dict import"); + TestUtils.assertFileNotContains(model, "_legacy_model_helpers import"); Assert.assertFalse(Files.exists(Paths.get( - outputPath + "openapi_client/_legacy_model_dict.py"))); + outputPath + "openapi_client/_legacy_model_helpers.py"))); } finally { if (oldModels == null) { GlobalSettings.clearProperty(CodegenConstants.MODELS); diff --git a/samples/client/others/python-legacy-model-dictionaries/.openapi-generator/FILES b/samples/client/others/python-legacy-model-dictionaries/.openapi-generator/FILES index dd90bb9c2eff..1e63ef27713b 100644 --- a/samples/client/others/python-legacy-model-dictionaries/.openapi-generator/FILES +++ b/samples/client/others/python-legacy-model-dictionaries/.openapi-generator/FILES @@ -12,6 +12,7 @@ docs/NestedModel.md docs/OneOfModel.md git_push.sh legacy_model_dict_client/__init__.py +legacy_model_dict_client/_legacy_model_helpers.py legacy_model_dict_client/api/__init__.py legacy_model_dict_client/api/default_api.py legacy_model_dict_client/api_client.py diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/_legacy_model_helpers.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/_legacy_model_helpers.py new file mode 100644 index 000000000000..100b33a6b0ba --- /dev/null +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/_legacy_model_helpers.py @@ -0,0 +1,80 @@ +""" + Legacy model dictionaries + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + The version of the OpenAPI document: 1.0.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from typing import Any + +_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" + + +def _get_openapi_to_dict(value: Any) -> Any: + # Reciprocal function references preserve inherited generated methods + # without reserving model member names. Checking both directions also + # rejects overrides whose decorators copy function attributes. + to_dict = getattr(value, "to_dict", None) + type_to_dict = getattr(type(value), "to_dict", None) + if ( + not callable(to_dict) + or getattr(to_dict, "__func__", None) is not type_to_dict + ): + return None + + openapi_to_dict = getattr( + type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None + ) + if ( + not callable(openapi_to_dict) + or getattr( + openapi_to_dict, + _OPENAPI_GENERATOR_TO_DICT, + None, + ) is not type_to_dict + ): + return None + return openapi_to_dict + + +def _to_legacy_item(value: Any, serialize: bool) -> Any: + to_dict = getattr(value, "to_dict", None) + if _get_openapi_to_dict(value) is not None and callable(to_dict): + return to_dict(serialize=serialize) + if callable(to_dict): + return to_dict() + return value + + +def _to_legacy_value(value: Any, serialize: bool) -> Any: + # python-legacy converted only immediate list elements or dictionary values: + # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 + if isinstance(value, list): + return [_to_legacy_item(item, serialize) for item in value] + if isinstance(value, dict): + return { + key: _to_legacy_item(item, serialize) + for key, item in value.items() + } + return _to_legacy_item(value, serialize) + + +def _to_openapi_value(value: Any) -> Any: + if isinstance(value, list): + return [_to_openapi_value(item) for item in value] + if isinstance(value, dict): + return {key: _to_openapi_value(item) for key, item in value.items()} + + to_openapi_dict = _get_openapi_to_dict(value) + if to_openapi_dict is not None: + return to_openapi_dict(value) + + to_dict = getattr(value, "to_dict", None) + if callable(to_dict): + return to_dict() + return value diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py index baab728d4dd5..6c65f993217d 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py @@ -44,34 +44,7 @@ ) -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict +from legacy_model_dict_client._legacy_model_helpers import _get_openapi_to_dict RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/additional_properties_model.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/additional_properties_model.py index 8b6f9ffd09f4..402c23f390fe 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/additional_properties_model.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/additional_properties_model.py @@ -25,72 +25,12 @@ from pydantic_core import to_jsonable_python -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict - - -def _to_legacy_item(value: Any, serialize: bool) -> Any: - to_dict = getattr(value, "to_dict", None) - if _get_openapi_to_dict(value) is not None and callable(to_dict): - return to_dict(serialize=serialize) - if callable(to_dict): - return to_dict() - return value - - -def _to_legacy_value(value: Any, serialize: bool) -> Any: - # python-legacy converted only immediate list elements or dictionary values: - # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 - if isinstance(value, list): - return [_to_legacy_item(item, serialize) for item in value] - if isinstance(value, dict): - return { - key: _to_legacy_item(item, serialize) - for key, item in value.items() - } - return _to_legacy_item(value, serialize) - - -def _to_openapi_value(value: Any) -> Any: - if isinstance(value, list): - return [_to_openapi_value(item) for item in value] - if isinstance(value, dict): - return {key: _to_openapi_value(item) for key, item in value.items()} - - to_openapi_dict = _get_openapi_to_dict(value) - if to_openapi_dict is not None: - return to_openapi_dict(value) - - to_dict = getattr(value, "to_dict", None) - if callable(to_dict): - return to_dict() - return value +from legacy_model_dict_client._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) class AdditionalPropertiesModel(BaseModel): diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/any_of_model.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/any_of_model.py index a3bf6fd9d696..52c806603cb7 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/any_of_model.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/any_of_model.py @@ -27,72 +27,12 @@ from pydantic_core import to_jsonable_python -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict - - -def _to_legacy_item(value: Any, serialize: bool) -> Any: - to_dict = getattr(value, "to_dict", None) - if _get_openapi_to_dict(value) is not None and callable(to_dict): - return to_dict(serialize=serialize) - if callable(to_dict): - return to_dict() - return value - - -def _to_legacy_value(value: Any, serialize: bool) -> Any: - # python-legacy converted only immediate list elements or dictionary values: - # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 - if isinstance(value, list): - return [_to_legacy_item(item, serialize) for item in value] - if isinstance(value, dict): - return { - key: _to_legacy_item(item, serialize) - for key, item in value.items() - } - return _to_legacy_item(value, serialize) - - -def _to_openapi_value(value: Any) -> Any: - if isinstance(value, list): - return [_to_openapi_value(item) for item in value] - if isinstance(value, dict): - return {key: _to_openapi_value(item) for key, item in value.items()} - - to_openapi_dict = _get_openapi_to_dict(value) - if to_openapi_dict is not None: - return to_openapi_dict(value) - - to_dict = getattr(value, "to_dict", None) - if callable(to_dict): - return to_dict() - return value +from legacy_model_dict_client._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) ANYOFMODEL_ANY_OF_SCHEMAS = ["Dict[str, NestedModel]", "LegacyModel", "List[NestedModel]", "str"] diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_base.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_base.py index 93770b240ce8..5d0b9713ad9f 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_base.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_base.py @@ -25,72 +25,12 @@ from pydantic_core import to_jsonable_python -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict - - -def _to_legacy_item(value: Any, serialize: bool) -> Any: - to_dict = getattr(value, "to_dict", None) - if _get_openapi_to_dict(value) is not None and callable(to_dict): - return to_dict(serialize=serialize) - if callable(to_dict): - return to_dict() - return value - - -def _to_legacy_value(value: Any, serialize: bool) -> Any: - # python-legacy converted only immediate list elements or dictionary values: - # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 - if isinstance(value, list): - return [_to_legacy_item(item, serialize) for item in value] - if isinstance(value, dict): - return { - key: _to_legacy_item(item, serialize) - for key, item in value.items() - } - return _to_legacy_item(value, serialize) - - -def _to_openapi_value(value: Any) -> Any: - if isinstance(value, list): - return [_to_openapi_value(item) for item in value] - if isinstance(value, dict): - return {key: _to_openapi_value(item) for key, item in value.items()} - - to_openapi_dict = _get_openapi_to_dict(value) - if to_openapi_dict is not None: - return to_openapi_dict(value) - - to_dict = getattr(value, "to_dict", None) - if callable(to_dict): - return to_dict() - return value +from legacy_model_dict_client._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) class LegacyBase(BaseModel): diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_model.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_model.py index d64b16847e2c..0378f5dc487f 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_model.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/legacy_model.py @@ -27,72 +27,12 @@ from typing import TYPE_CHECKING -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict - - -def _to_legacy_item(value: Any, serialize: bool) -> Any: - to_dict = getattr(value, "to_dict", None) - if _get_openapi_to_dict(value) is not None and callable(to_dict): - return to_dict(serialize=serialize) - if callable(to_dict): - return to_dict() - return value - - -def _to_legacy_value(value: Any, serialize: bool) -> Any: - # python-legacy converted only immediate list elements or dictionary values: - # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 - if isinstance(value, list): - return [_to_legacy_item(item, serialize) for item in value] - if isinstance(value, dict): - return { - key: _to_legacy_item(item, serialize) - for key, item in value.items() - } - return _to_legacy_item(value, serialize) - - -def _to_openapi_value(value: Any) -> Any: - if isinstance(value, list): - return [_to_openapi_value(item) for item in value] - if isinstance(value, dict): - return {key: _to_openapi_value(item) for key, item in value.items()} - - to_openapi_dict = _get_openapi_to_dict(value) - if to_openapi_dict is not None: - return to_openapi_dict(value) - - to_dict = getattr(value, "to_dict", None) - if callable(to_dict): - return to_dict() - return value +from legacy_model_dict_client._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) class LegacyModel(BaseModel): diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/nested_model.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/nested_model.py index 0a9343993be1..25a8613393b9 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/nested_model.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/nested_model.py @@ -25,72 +25,12 @@ from pydantic_core import to_jsonable_python -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict - - -def _to_legacy_item(value: Any, serialize: bool) -> Any: - to_dict = getattr(value, "to_dict", None) - if _get_openapi_to_dict(value) is not None and callable(to_dict): - return to_dict(serialize=serialize) - if callable(to_dict): - return to_dict() - return value - - -def _to_legacy_value(value: Any, serialize: bool) -> Any: - # python-legacy converted only immediate list elements or dictionary values: - # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 - if isinstance(value, list): - return [_to_legacy_item(item, serialize) for item in value] - if isinstance(value, dict): - return { - key: _to_legacy_item(item, serialize) - for key, item in value.items() - } - return _to_legacy_item(value, serialize) - - -def _to_openapi_value(value: Any) -> Any: - if isinstance(value, list): - return [_to_openapi_value(item) for item in value] - if isinstance(value, dict): - return {key: _to_openapi_value(item) for key, item in value.items()} - - to_openapi_dict = _get_openapi_to_dict(value) - if to_openapi_dict is not None: - return to_openapi_dict(value) - - to_dict = getattr(value, "to_dict", None) - if callable(to_dict): - return to_dict() - return value +from legacy_model_dict_client._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) class NestedModel(BaseModel): diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/one_of_model.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/one_of_model.py index 57bebc2c3e6e..b76545cb241a 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/one_of_model.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/models/one_of_model.py @@ -25,72 +25,12 @@ from pydantic_core import to_jsonable_python -_OPENAPI_GENERATOR_TO_DICT = "_openapi_generator_to_dict" - - -def _get_openapi_to_dict(value: Any) -> Any: - # Reciprocal function references preserve inherited generated methods - # without reserving model member names. Checking both directions also - # rejects overrides whose decorators copy function attributes. - to_dict = getattr(value, "to_dict", None) - type_to_dict = getattr(type(value), "to_dict", None) - if ( - not callable(to_dict) - or getattr(to_dict, "__func__", None) is not type_to_dict - ): - return None - - openapi_to_dict = getattr( - type_to_dict, _OPENAPI_GENERATOR_TO_DICT, None - ) - if ( - not callable(openapi_to_dict) - or getattr( - openapi_to_dict, - _OPENAPI_GENERATOR_TO_DICT, - None, - ) is not type_to_dict - ): - return None - return openapi_to_dict - - -def _to_legacy_item(value: Any, serialize: bool) -> Any: - to_dict = getattr(value, "to_dict", None) - if _get_openapi_to_dict(value) is not None and callable(to_dict): - return to_dict(serialize=serialize) - if callable(to_dict): - return to_dict() - return value - - -def _to_legacy_value(value: Any, serialize: bool) -> Any: - # python-legacy converted only immediate list elements or dictionary values: - # https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb49b45c940c2f694/modules/openapi-generator/src/main/resources/python-legacy/model.mustache#L203-L231 - if isinstance(value, list): - return [_to_legacy_item(item, serialize) for item in value] - if isinstance(value, dict): - return { - key: _to_legacy_item(item, serialize) - for key, item in value.items() - } - return _to_legacy_item(value, serialize) - - -def _to_openapi_value(value: Any) -> Any: - if isinstance(value, list): - return [_to_openapi_value(item) for item in value] - if isinstance(value, dict): - return {key: _to_openapi_value(item) for key, item in value.items()} - - to_openapi_dict = _get_openapi_to_dict(value) - if to_openapi_dict is not None: - return to_openapi_dict(value) - - to_dict = getattr(value, "to_dict", None) - if callable(to_dict): - return to_dict() - return value +from legacy_model_dict_client._legacy_model_helpers import ( + _OPENAPI_GENERATOR_TO_DICT, + _get_openapi_to_dict, + _to_legacy_value, + _to_openapi_value, +) ONEOFMODEL_ONE_OF_SCHEMAS = ["Dict[str, NestedModel]", "LegacyModel", "List[NestedModel]", "str"]