From d27cc40ae7b3902f4c332ce32f90a8e0dce9932f Mon Sep 17 00:00:00 2001 From: Swapneswar Sundar Ray Date: Sat, 2 May 2026 01:04:28 -0400 Subject: [PATCH 1/3] Fix Python PATCH serialization for unset default fields --- .../codegen/languages/PythonClientCodegen.java | 14 ++++++++++++++ .../main/resources/python/model_generic.mustache | 11 +++++++++++ 2 files changed, 25 insertions(+) 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 fdf19feff107..a70bd16d120e 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 @@ -25,6 +25,8 @@ import org.openapitools.codegen.meta.GeneratorMetadata; import org.openapitools.codegen.meta.Stability; import org.openapitools.codegen.meta.features.*; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.ModelsMap; import org.openapitools.codegen.utils.ModelUtils; import org.openapitools.codegen.utils.ProcessUtils; import org.slf4j.Logger; @@ -434,6 +436,18 @@ public String modelTestFileFolder() { return outputFolder + File.separatorChar + testFolder; } + @Override + public ModelsMap postProcessModels(ModelsMap objs) { + // Process models to detect PATCH models (models starting with 'Patched') + for (ModelMap mo : objs.getModels()) { + CodegenModel cm = mo.getModel(); + if (cm.getClassname().startsWith("Patched")) { + cm.vendorExtensions.put("isPatchedModel", true); + } + } + return super.postProcessModels(objs); + } + public String packagePath() { return packageName.replace('.', File.separatorChar); } 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 1b9d0f7d3fd8..dd42bbcd03e5 100644 --- a/modules/openapi-generator/src/main/resources/python/model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/python/model_generic.mustache @@ -164,11 +164,22 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/isAdditionalPropertiesTrue}} ]) + {{#classname}} + {{#isPatchedModel}} + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_unset=True, # For PATCH models, exclude unset fields to avoid sending default values + ) + {{/isPatchedModel}} + {{^isPatchedModel}} _dict = self.model_dump( by_alias=True, exclude=excluded_fields, exclude_none=True, ) + {{/isPatchedModel}} +{{/classname}} {{#allVars}} {{#isContainer}} {{#isArray}} From a3ec44ec0b95572a761f1b124e8be7c1edc2be73 Mon Sep 17 00:00:00 2001 From: Swapneswar Sundar Ray Date: Sat, 2 May 2026 09:55:05 -0400 Subject: [PATCH 2/3] fix(python): Use exclude_unset=True for PATCH models Prevents sending default values in PATCH requests when fields are not explicitly set by the client. Only affects models starting with 'Patched'. Fixes #23650 --- .../codegen/languages/PythonClientCodegen.java | 1 + .../src/main/resources/python/model_generic.mustache | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) 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 a70bd16d120e..98e88259c29c 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 @@ -442,6 +442,7 @@ public ModelsMap postProcessModels(ModelsMap objs) { for (ModelMap mo : objs.getModels()) { CodegenModel cm = mo.getModel(); if (cm.getClassname().startsWith("Patched")) { + // Mark as PATCH model for template handling cm.vendorExtensions.put("isPatchedModel", true); } } 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 dd42bbcd03e5..7856b1ff5550 100644 --- a/modules/openapi-generator/src/main/resources/python/model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/python/model_generic.mustache @@ -164,22 +164,20 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/isAdditionalPropertiesTrue}} ]) - {{#classname}} - {{#isPatchedModel}} + {{#vendorExtensions.isPatchedModel}} _dict = self.model_dump( by_alias=True, exclude=excluded_fields, exclude_unset=True, # For PATCH models, exclude unset fields to avoid sending default values ) - {{/isPatchedModel}} - {{^isPatchedModel}} +{{/vendorExtensions.isPatchedModel}} +{{^vendorExtensions.isPatchedModel}} _dict = self.model_dump( by_alias=True, exclude=excluded_fields, exclude_none=True, ) - {{/isPatchedModel}} -{{/classname}} +{{/vendorExtensions.isPatchedModel}} {{#allVars}} {{#isContainer}} {{#isArray}} From 2d3bd2ec57b5148f6e6adfba6634b19aaecaa6c5 Mon Sep 17 00:00:00 2001 From: Swapneswar Sundar Ray Date: Sat, 2 May 2026 10:35:37 -0400 Subject: [PATCH 3/3] fixes #23650(python): Clean up Mustache template condition to prevent broken output Fixed improper indentation in Mustache template that could cause broken Python code generation. Now uses inline conditions within method call instead of duplicated method blocks. --- .../src/main/resources/python/model_generic.mustache | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) 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 7856b1ff5550..a5d695dee505 100644 --- a/modules/openapi-generator/src/main/resources/python/model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/python/model_generic.mustache @@ -164,20 +164,16 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} {{/isAdditionalPropertiesTrue}} ]) - {{#vendorExtensions.isPatchedModel}} _dict = self.model_dump( by_alias=True, exclude=excluded_fields, + {{#vendorExtensions.isPatchedModel}} exclude_unset=True, # For PATCH models, exclude unset fields to avoid sending default values - ) -{{/vendorExtensions.isPatchedModel}} -{{^vendorExtensions.isPatchedModel}} - _dict = self.model_dump( - by_alias=True, - exclude=excluded_fields, + {{/vendorExtensions.isPatchedModel}} + {{^vendorExtensions.isPatchedModel}} exclude_none=True, + {{/vendorExtensions.isPatchedModel}} ) -{{/vendorExtensions.isPatchedModel}} {{#allVars}} {{#isContainer}} {{#isArray}}