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 b38d2448d87..3b0b5deeb81 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 @@ -36,6 +36,8 @@ import org.openapitools.codegen.meta.Stability; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.curiousoddman.rgxgen.RgxGen; +import com.github.curiousoddman.rgxgen.config.RgxGenOption; +import com.github.curiousoddman.rgxgen.config.RgxGenProperties; import java.time.OffsetDateTime; import java.time.ZoneOffset; @@ -894,6 +896,13 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { return "\"" + in + "\""; } + @Override + public String toExampleValue(Schema schema) { + Object objExample = getObjectExample(schema); + String modelName = getModelName(schema); + return toExampleValueRecursive(modelName, schema, objExample, 1, "", 0, Sets.newHashSet()); + } + public String toExampleValue(Schema schema, Object objExample) { String modelName = getModelName(schema); return toExampleValueRecursive(modelName, schema, objExample, 1, "", 0, Sets.newHashSet()); @@ -974,7 +983,7 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { // checks if the current schema has already been passed in. If so, breaks the current recursive pass if (seenSchemas.contains(schema)) { if (modelName != null) { - return fullPrefix + modelName + closeChars; + return fullPrefix + closeChars; } else { // this is a recursive schema // need to add a reasonable example to avoid @@ -1050,18 +1059,39 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { return fullPrefix + example + closeChars; } else if (StringUtils.isNotBlank(schema.getPattern())) { String pattern = schema.getPattern(); - RgxGen rgxGen = new RgxGen(pattern); + /* + RxGen does not support our ECMA dialect https://github.com/curious-odd-man/RgxGen/issues/56 + So strip off the leading / and trailing / and turn on ignore case if we have it + */ + Pattern valueExtractor = Pattern.compile("^/?(.+?)/?(.?)$"); + Matcher m = valueExtractor.matcher(pattern); + RgxGen rgxGen = null; + if (m.find()) { + int groupCount = m.groupCount(); + if (groupCount == 1) { + // only pattern found + String isolatedPattern = m.group(1); + rgxGen = new RgxGen(isolatedPattern); + } else if (groupCount == 2) { + // patterns and flag found + String isolatedPattern = m.group(1); + String flags = m.group(2); + if (flags.contains("i")) { + rgxGen = new RgxGen(isolatedPattern); + RgxGenProperties properties = new RgxGenProperties(); + RgxGenOption.CASE_INSENSITIVE.setInProperties(properties, true); + rgxGen.setProperties(properties); + } else { + rgxGen = new RgxGen(isolatedPattern); + } + } + } else { + rgxGen = new RgxGen(pattern); + } + // this seed makes it so if we have [a-z] we pick a Random random = new Random(18); - String sample = rgxGen.generate(random); - // omit leading / and trailing /, omit trailing /i - Pattern valueExtractor = Pattern.compile("^/?(.+?)/?.?$"); - Matcher m = valueExtractor.matcher(sample); - if (m.find()) { - example = m.group(m.groupCount()); - } else { - example = ""; - } + example = rgxGen.generate(random); } else if (schema.getMinLength() != null) { example = ""; int len = schema.getMinLength().intValue(); @@ -1099,8 +1129,9 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { // If the example is already a list, return it directly instead of wrongly wrap it in another list return fullPrefix + objExample.toString() + closeChars; } - seenSchemas.add(schema); - example = fullPrefix + "[" + "\n" + toExampleValueRecursive(itemModelName, itemSchema, objExample, indentationLevel + 1, "", exampleLine + 1, seenSchemas) + ",\n" + closingIndentation + "]" + closeChars; + Set newSeenSchemas = new HashSet<>(seenSchemas); + newSeenSchemas.add(schema); + example = fullPrefix + "[" + "\n" + toExampleValueRecursive(itemModelName, itemSchema, objExample, indentationLevel + 1, "", exampleLine + 1, newSeenSchemas) + ",\n" + closingIndentation + "]" + closeChars; return example; } else if (ModelUtils.isMapSchema(schema)) { if (modelName == null) { @@ -1122,8 +1153,9 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { addPropPrefix = ensureQuotes(key) + ": "; } String addPropsModelName = getModelName(addPropsSchema); - seenSchemas.add(schema); - example = fullPrefix + "\n" + toExampleValueRecursive(addPropsModelName, addPropsSchema, addPropsExample, indentationLevel + 1, addPropPrefix, exampleLine + 1, seenSchemas) + ",\n" + closingIndentation + closeChars; + Set newSeenSchemas = new HashSet<>(seenSchemas); + newSeenSchemas.add(schema); + example = fullPrefix + "\n" + toExampleValueRecursive(addPropsModelName, addPropsSchema, addPropsExample, indentationLevel + 1, addPropPrefix, exampleLine + 1, newSeenSchemas) + ",\n" + closingIndentation + closeChars; } else { example = fullPrefix + closeChars; } @@ -1146,11 +1178,9 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { return fullPrefix + closeChars; } } - // Adds schema to seenSchemas before running example model function. romoves schema after running - // the function. It also doesnt keep track of any schemas within the ObjectModel. - seenSchemas.add(schema); - String exampleForObjectModel = exampleForObjectModel(schema, fullPrefix, closeChars, null, indentationLevel, exampleLine, closingIndentation, seenSchemas); - seenSchemas.remove(schema); + Set newSeenSchemas = new HashSet<>(seenSchemas); + newSeenSchemas.add(schema); + String exampleForObjectModel = exampleForObjectModel(schema, fullPrefix, closeChars, null, indentationLevel, exampleLine, closingIndentation, newSeenSchemas); return exampleForObjectModel; } else if (ModelUtils.isComposedSchema(schema)) { // TODO add examples for composed schema models without discriminators @@ -1167,9 +1197,9 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { cp.setExample(discPropNameValue); // Adds schema to seenSchemas before running example model function. romoves schema after running // the function. It also doesnt keep track of any schemas within the ObjectModel. - seenSchemas.add(modelSchema); - String exampleForObjectModel = exampleForObjectModel(modelSchema, fullPrefix, closeChars, cp, indentationLevel, exampleLine, closingIndentation, seenSchemas); - seenSchemas.remove(modelSchema); + Set newSeenSchemas = new HashSet<>(seenSchemas); + newSeenSchemas.add(schema); + String exampleForObjectModel = exampleForObjectModel(modelSchema, fullPrefix, closeChars, cp, indentationLevel, exampleLine, closingIndentation, newSeenSchemas); return exampleForObjectModel; } else { return fullPrefix + closeChars; diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java index 7d5cc631a8b..8a213a37757 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java @@ -17,6 +17,7 @@ package org.openapitools.codegen.languages; +import io.swagger.v3.oas.models.media.Schema; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.*; import org.openapitools.codegen.meta.features.*; @@ -430,5 +431,4 @@ public class PythonLegacyClientCodegen extends AbstractPythonCodegen implements public String generatePackageName(String packageName) { return underscore(packageName.replaceAll("[^\\w]+", "")); } - } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientTest.java index 4face161d7e..842d6a2851a 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientTest.java @@ -460,7 +460,7 @@ public class PythonClientTest { expectedValue = expectedValue.replaceAll("\\r\\n", "\n"); - Assert.assertEquals(expectedValue.trim(), exampleValue.trim()); + Assert.assertEquals(exampleValue.trim(), expectedValue.trim()); } diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_8052_recursive_model_expected_value.txt b/modules/openapi-generator/src/test/resources/3_0/issue_8052_recursive_model_expected_value.txt index 98ef62651fb..aad2924c9db 100644 --- a/modules/openapi-generator/src/test/resources/3_0/issue_8052_recursive_model_expected_value.txt +++ b/modules/openapi-generator/src/test/resources/3_0/issue_8052_recursive_model_expected_value.txt @@ -1,9 +1,6 @@ GeoJsonGeometry( type="GeometryCollection", geometries=[ - GeoJsonGeometry( - type="GeometryCollection", - geometries=[], - ), + GeoJsonGeometry(), ], ) \ No newline at end of file diff --git a/samples/client/petstore/python/docs/FakeApi.md b/samples/client/petstore/python/docs/FakeApi.md index a107342b75c..bfd6467215b 100644 --- a/samples/client/petstore/python/docs/FakeApi.md +++ b/samples/client/petstore/python/docs/FakeApi.md @@ -842,13 +842,13 @@ with petstore_api.ApiClient(configuration) as api_client: api_instance = fake_api.FakeApi(api_client) number = 32.1 # float | None double = 67.8 # float | None - pattern_without_delimiter = "AUR,rZ#UM/?R,Fp^l6$ARjbhJk C" # str | None + pattern_without_delimiter = "Aj" # str | None byte = 'YQ==' # str | None integer = 10 # int | None (optional) int32 = 20 # int | None (optional) int64 = 1 # int | None (optional) float = 3.14 # float | None (optional) - string = "a" # str | None (optional) + string = "A" # str | None (optional) binary = open('/path/to/file', 'rb') # file_type | None (optional) date = dateutil_parser('1970-01-01').date() # date | None (optional) date_time = dateutil_parser('1970-01-01T00:00:00.00Z') # datetime | None (optional) diff --git a/samples/openapi3/client/petstore/python/docs/FakeApi.md b/samples/openapi3/client/petstore/python/docs/FakeApi.md index ea6886d682b..3bb042e8845 100644 --- a/samples/openapi3/client/petstore/python/docs/FakeApi.md +++ b/samples/openapi3/client/petstore/python/docs/FakeApi.md @@ -1146,13 +1146,13 @@ with petstore_api.ApiClient(configuration) as api_client: api_instance = fake_api.FakeApi(api_client) number = 32.1 # float | None double = 67.8 # float | None - pattern_without_delimiter = "AUR,rZ#UM/?R,Fp^l6$ARjbhJk C" # str | None + pattern_without_delimiter = "Aj" # str | None byte = 'YQ==' # str | None integer = 10 # int | None (optional) int32 = 20 # int | None (optional) int64 = 1 # int | None (optional) float = 3.14 # float | None (optional) - string = "a" # str | None (optional) + string = "A" # str | None (optional) binary = open('/path/to/file', 'rb') # file_type | None (optional) date = dateutil_parser('1970-01-01').date() # date | None (optional) date_time = dateutil_parser('2020-02-02T20:20:20.22222Z') # datetime | None (optional) if omitted the server will use the default value of dateutil_parser('2010-02-01T10:20:10.11111+01:00')