diff --git a/src/main/resources/handlebars/python/model.mustache b/src/main/resources/handlebars/python/model.mustache index 5ef0d319f9..209410f729 100644 --- a/src/main/resources/handlebars/python/model.mustache +++ b/src/main/resources/handlebars/python/model.mustache @@ -129,10 +129,10 @@ class {{classname}}({{#parent}}{{parent}}{{/parent}}{{^parent}}object{{/parent}} ) {{/isListContainer}} {{#isMapContainer}} - if not set({{{name}}}.keys()).issubset(set(allowed_values)): + if not set({{{name}}}.values()).issubset(set(allowed_values)): raise ValueError( - "Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 - .format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501 + "Invalid values in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 + .format(", ".join(map(str, set({{{name}}}.values()) - set(allowed_values))), # noqa: E501 ", ".join(map(str, allowed_values))) ) {{/isMapContainer}} diff --git a/src/main/resources/handlebars/pythonFlaskConnexion/model.mustache b/src/main/resources/handlebars/pythonFlaskConnexion/model.mustache index 2a2a6ba71c..35a2ec2850 100644 --- a/src/main/resources/handlebars/pythonFlaskConnexion/model.mustache +++ b/src/main/resources/handlebars/pythonFlaskConnexion/model.mustache @@ -99,10 +99,10 @@ class {{classname}}(Model): ) {{/isListContainer}} {{#isMapContainer}} - if not set({{{name}}}.keys()).issubset(set(allowed_values)): + if not set({{{name}}}.values()).issubset(set(allowed_values)): raise ValueError( - "Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 - .format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501 + "Invalid values in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 + .format(", ".join(map(str, set({{{name}}}.values()) - set(allowed_values))), # noqa: E501 ", ".join(map(str, allowed_values))) ) {{/isMapContainer}} diff --git a/src/test/java/io/swagger/codegen/v3/generators/python/PythonMapEnumValidationTest.java b/src/test/java/io/swagger/codegen/v3/generators/python/PythonMapEnumValidationTest.java new file mode 100644 index 0000000000..805e082368 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/python/PythonMapEnumValidationTest.java @@ -0,0 +1,60 @@ +package io.swagger.codegen.v3.generators.python; + +import io.swagger.codegen.v3.generators.GeneratorRunner; +import io.swagger.codegen.v3.service.GenerationRequest; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +/** + * Regression test for the Python generator `Map<String, Enum>` setter validation. + * + *

The {@code model.mustache} template used to emit + * {@code set(x.keys()).issubset(allowed_values)} for properties declared as + * {@code type: object} with {@code additionalProperties.enum}. Per OpenAPI 3.0 + * semantics, {@code additionalProperties} describes map values, so the enum + * constraint applies to the values, not the keys. The fix validates + * {@code set(x.values()).issubset(allowed_values)} and updates the error message + * from "Invalid keys in" to "Invalid values in". + */ +public class PythonMapEnumValidationTest { + + @Test + public void mapOfEnumSetterValidatesValuesNotKeys() throws Exception { + final List files = GeneratorRunner.runGenerator( + "python", + "3_0_0/map_of_inner_enum.yaml", + GenerationRequest.CodegenVersion.V3, + false, + true, + true, + null, + options -> {}); + + Assert.assertFalse(files.isEmpty()); + + final File modelFile = files.stream() + .filter(f -> f.getName().equals("employee_with_map_of_enum.py")) + .findFirst() + .orElseThrow(() -> new RuntimeException("employee_with_map_of_enum.py was not generated")); + + final String content = new String(Files.readAllBytes(Paths.get(modelFile.toURI()))); + + Assert.assertTrue( + content.contains("set(project_role.values()).issubset(set(allowed_values))"), + "Setter should validate map values (not keys) against the enum.\nGenerated:\n" + content); + Assert.assertTrue( + content.contains("Invalid values in `project_role`"), + "Setter error message should reference 'Invalid values in'.\nGenerated:\n" + content); + Assert.assertFalse( + content.contains("set(project_role.keys()).issubset(set(allowed_values))"), + "Setter must not validate map keys against the enum.\nGenerated:\n" + content); + Assert.assertFalse( + content.contains("Invalid keys in `project_role`"), + "Setter error message must not reference 'Invalid keys in'.\nGenerated:\n" + content); + } +}