Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python-nextgen] Add support for union of StrictFloat and StrictInt #15124

Merged
merged 1 commit into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/configs/python-nextgen-aiohttp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ templateDir: modules/openapi-generator/src/main/resources/python-nextgen
library: asyncio
additionalProperties:
packageName: petstore_api
floatStrictType: false
mapNumberTo: float
1 change: 1 addition & 0 deletions bin/configs/python-nextgen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ additionalProperties:
packageName: petstore_api
useOneOfDiscriminatorLookup: "true"
disallowAdditionalPropertiesIfNotPresent: false
mapNumberTo: StrictFloat
2 changes: 1 addition & 1 deletion docs/generators/python-nextgen.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|dateFormat|date format for query parameters| |%Y-%m-%d|
|datetimeFormat|datetime format for query parameters| |%Y-%m-%dT%H:%M:%S%z|
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.</dd></dl>|true|
|floatStrictType|Use strict type for float, i.e. StrictFloat or confloat(strict=true, ...)| |true|
|generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|library|library template (sub-template) to use: asyncio, tornado (deprecated), urllib3| |urllib3|
|mapNumberTo|Map number to Union[StrictFloat, StrictInt], StrictStr or float.| |Union[StrictFloat, StrictInt]|
|packageName|python package name (convention: snake_case).| |openapi_client|
|packageUrl|python package URL.| |null|
|packageVersion|python package version.| |1.0.0|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,18 @@ public class PythonNextgenClientCodegen extends AbstractPythonCodegen implements
public static final String PACKAGE_URL = "packageUrl";
public static final String DEFAULT_LIBRARY = "urllib3";
public static final String RECURSION_LIMIT = "recursionLimit";
public static final String FLOAT_STRICT_TYPE = "floatStrictType";
public static final String DATETIME_FORMAT = "datetimeFormat";
public static final String DATE_FORMAT = "dateFormat";
public static final String MAP_NUMBER_TO = "mapNumberTo";

protected String packageUrl;
protected String apiDocPath = "docs" + File.separator;
protected String modelDocPath = "docs" + File.separator;
protected boolean hasModelsToImport = Boolean.FALSE;
protected boolean useOneOfDiscriminatorLookup = false; // use oneOf discriminator's mapping for model lookup
protected boolean floatStrictType = true;
protected String datetimeFormat = "%Y-%m-%dT%H:%M:%S.%f%z";
protected String dateFormat = "%Y-%m-%d";
protected String mapNumberTo = "Union[StrictFloat, StrictInt]";

protected Map<Character, String> regexModifiers;

Expand Down Expand Up @@ -177,8 +177,8 @@ public PythonNextgenClientCodegen() {
cliOptions.add(new CliOption(CodegenConstants.SOURCECODEONLY_GENERATION, CodegenConstants.SOURCECODEONLY_GENERATION_DESC)
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(RECURSION_LIMIT, "Set the recursion limit. If not set, use the system default value."));
cliOptions.add(new CliOption(FLOAT_STRICT_TYPE, "Use strict type for float, i.e. StrictFloat or confloat(strict=true, ...)")
.defaultValue(Boolean.TRUE.toString()));
cliOptions.add(new CliOption(MAP_NUMBER_TO, "Map number to Union[StrictFloat, StrictInt], StrictStr or float.")
.defaultValue("Union[StrictFloat, StrictInt]"));
cliOptions.add(new CliOption(DATETIME_FORMAT, "datetime format for query parameters")
.defaultValue("%Y-%m-%dT%H:%M:%S%z"));
cliOptions.add(new CliOption(DATE_FORMAT, "date format for query parameters")
Expand Down Expand Up @@ -281,8 +281,8 @@ public void processOpts() {
additionalProperties.put(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, useOneOfDiscriminatorLookup);
}

if (additionalProperties.containsKey(FLOAT_STRICT_TYPE)) {
setFloatStrictType(convertPropertyToBooleanAndWriteBack(FLOAT_STRICT_TYPE));
if (additionalProperties.containsKey(MAP_NUMBER_TO)) {
setMapNumberTo(String.valueOf(additionalProperties.get(MAP_NUMBER_TO)));
}

if (additionalProperties.containsKey(DATETIME_FORMAT)) {
Expand Down Expand Up @@ -478,34 +478,59 @@ private String getPydanticType(CodegenParameter cp,
} else if (cp.isNumber || cp.isFloat || cp.isDouble) {
if (cp.hasValidation) {
List<String> fieldCustomization = new ArrayList<>();
List<String> intFieldCustomization = new ArrayList<>();

// e.g. confloat(ge=10, le=100, strict=True)
if (cp.getMaximum() != null) {
if (cp.getExclusiveMaximum()) {
fieldCustomization.add("gt=" + cp.getMaximum());
fieldCustomization.add("lt=" + cp.getMaximum());
intFieldCustomization.add("lt=" + Math.ceil(Double.valueOf(cp.getMaximum()))); // e.g. < 7.59 becomes < 8
} else {
fieldCustomization.add("ge=" + cp.getMaximum());
fieldCustomization.add("le=" + cp.getMaximum());
intFieldCustomization.add("le=" + Math.floor(Double.valueOf(cp.getMaximum()))); // e.g. <= 7.59 becomes <= 7
}
}
if (cp.getMinimum() != null) {
if (cp.getExclusiveMinimum()) {
fieldCustomization.add("lt=" + cp.getMinimum());
fieldCustomization.add("gt=" + cp.getMinimum());
intFieldCustomization.add("gt=" + Math.floor(Double.valueOf(cp.getMinimum()))); // e.g. > 7.59 becomes > 7
} else {
fieldCustomization.add("le=" + cp.getMinimum());
fieldCustomization.add("ge=" + cp.getMinimum());
intFieldCustomization.add("ge=" + Math.ceil(Double.valueOf(cp.getMinimum()))); // e.g. >= 7.59 becomes >= 8
}
}
if (cp.getMultipleOf() != null) {
fieldCustomization.add("multiple_of=" + cp.getMultipleOf());
}

if (floatStrictType) {
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
fieldCustomization.add("strict=True");
intFieldCustomization.add("strict=True");
pydanticImports.add("confloat");
pydanticImports.add("conint");
typingImports.add("Union");
return String.format(Locale.ROOT, "Union[%s(%s), %s(%s)]", "confloat",
StringUtils.join(fieldCustomization, ", "),
"conint",
StringUtils.join(intFieldCustomization, ", ")
);
} else if ("StrictFloat".equals(mapNumberTo)) {
fieldCustomization.add("strict=True");
pydanticImports.add("confloat");
return String.format(Locale.ROOT, "%s(%s)", "confloat",
StringUtils.join(fieldCustomization, ", "));
} else { // float
pydanticImports.add("confloat");
return String.format(Locale.ROOT, "%s(%s)", "confloat",
StringUtils.join(fieldCustomization, ", "));
}

pydanticImports.add("confloat");
return String.format(Locale.ROOT, "%s(%s)", "confloat",
StringUtils.join(fieldCustomization, ", "));
} else {
if (floatStrictType) {
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
typingImports.add("Union");
pydanticImports.add("StrictFloat");
pydanticImports.add("StrictInt");
return "Union[StrictFloat, StrictInt]";
} else if ("StrictFloat".equals(mapNumberTo)) {
pydanticImports.add("StrictFloat");
return "StrictFloat";
} else {
Expand Down Expand Up @@ -723,34 +748,59 @@ private String getPydanticType(CodegenProperty cp,
} else if (cp.isNumber || cp.isFloat || cp.isDouble) {
if (cp.hasValidation) {
List<String> fieldCustomization = new ArrayList<>();
List<String> intFieldCustomization = new ArrayList<>();

// e.g. confloat(ge=10, le=100, strict=True)
if (cp.getMaximum() != null) {
if (cp.getExclusiveMaximum()) {
fieldCustomization.add("lt=" + cp.getMaximum());
intFieldCustomization.add("lt=" + (int) Math.ceil(Double.valueOf(cp.getMaximum()))); // e.g. < 7.59 => < 8
} else {
fieldCustomization.add("le=" + cp.getMaximum());
intFieldCustomization.add("le=" + (int) Math.floor(Double.valueOf(cp.getMaximum()))); // e.g. <= 7.59 => <= 7
}
}
if (cp.getMinimum() != null) {
if (cp.getExclusiveMinimum()) {
fieldCustomization.add("gt=" + cp.getMinimum());
intFieldCustomization.add("gt=" + (int) Math.floor(Double.valueOf(cp.getMinimum()))); // e.g. > 7.59 => > 7
} else {
fieldCustomization.add("ge=" + cp.getMinimum());
intFieldCustomization.add("ge=" + (int) Math.ceil(Double.valueOf(cp.getMinimum()))); // e.g. >= 7.59 => >= 8
}
}
if (cp.getMultipleOf() != null) {
fieldCustomization.add("multiple_of=" + cp.getMultipleOf());
}

if (floatStrictType) {
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
fieldCustomization.add("strict=True");
intFieldCustomization.add("strict=True");
pydanticImports.add("confloat");
pydanticImports.add("conint");
typingImports.add("Union");
return String.format(Locale.ROOT, "Union[%s(%s), %s(%s)]", "confloat",
StringUtils.join(fieldCustomization, ", "),
"conint",
StringUtils.join(intFieldCustomization, ", ")
);
} else if ("StrictFloat".equals(mapNumberTo)) {
fieldCustomization.add("strict=True");
pydanticImports.add("confloat");
return String.format(Locale.ROOT, "%s(%s)", "confloat",
StringUtils.join(fieldCustomization, ", "));
} else { // float
pydanticImports.add("confloat");
return String.format(Locale.ROOT, "%s(%s)", "confloat",
StringUtils.join(fieldCustomization, ", "));
}

pydanticImports.add("confloat");
return String.format(Locale.ROOT, "%s(%s)", "confloat",
StringUtils.join(fieldCustomization, ", "));
} else {
if (floatStrictType) {
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
typingImports.add("Union");
pydanticImports.add("StrictFloat");
pydanticImports.add("StrictInt");
return "Union[StrictFloat, StrictInt]";
} else if ("StrictFloat".equals(mapNumberTo)) {
pydanticImports.add("StrictFloat");
return "StrictFloat";
} else {
Expand Down Expand Up @@ -1334,8 +1384,8 @@ public void postProcessPattern(String pattern, Map<String, Object> vendorExtensi
}
}

vendorExtensions.put("x-regex", regex.replace("\"","\\\""));
vendorExtensions.put("x-pattern", pattern.replace("\"","\\\""));
vendorExtensions.put("x-regex", regex.replace("\"", "\\\""));
vendorExtensions.put("x-pattern", pattern.replace("\"", "\\\""));
vendorExtensions.put("x-modifiers", modifiers);
}
}
Expand Down Expand Up @@ -1529,8 +1579,14 @@ public String escapeReservedWord(String name) {
return "var_" + name;
}

public void setFloatStrictType(boolean floatStrictType) {
this.floatStrictType = floatStrictType;
public void setMapNumberTo(String mapNumberTo) {
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)
|| "StrictFloat".equals(mapNumberTo)
|| "float".equals(mapNumberTo)) {
this.mapNumberTo = mapNumberTo;
} else {
throw new IllegalArgumentException("mapNumberTo value must be Union[StrictFloat, StrictInt], StrictStr or float");
}
}

public void setDatetimeFormat(String datetimeFormat) {
Expand Down
13 changes: 13 additions & 0 deletions modules/openapi-generator/src/test/resources/3_0/echo_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -516,3 +516,16 @@ components:
format: date-time
description: A date
- $ref: '#/components/schemas/Query'
NumberPropertiesOnly:
type: object
properties:
number:
type: number
float:
type: number
format: float
double:
type: number
format: double
minimum: 0.8
maximum: 50.2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ docs/DataQueryAllOf.md
docs/DefaultValue.md
docs/FormApi.md
docs/HeaderApi.md
docs/NumberPropertiesOnly.md
docs/PathApi.md
docs/Pet.md
docs/Query.md
Expand Down Expand Up @@ -53,6 +54,7 @@ src/main/java/org/openapitools/client/model/Category.java
src/main/java/org/openapitools/client/model/DataQuery.java
src/main/java/org/openapitools/client/model/DataQueryAllOf.java
src/main/java/org/openapitools/client/model/DefaultValue.java
src/main/java/org/openapitools/client/model/NumberPropertiesOnly.java
src/main/java/org/openapitools/client/model/Pet.java
src/main/java/org/openapitools/client/model/Query.java
src/main/java/org/openapitools/client/model/StringEnumRef.java
Expand Down
1 change: 1 addition & 0 deletions samples/client/echo_api/java/apache-httpclient/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ Class | Method | HTTP request | Description
- [DataQuery](docs/DataQuery.md)
- [DataQueryAllOf](docs/DataQueryAllOf.md)
- [DefaultValue](docs/DefaultValue.md)
- [NumberPropertiesOnly](docs/NumberPropertiesOnly.md)
- [Pet](docs/Pet.md)
- [Query](docs/Query.md)
- [StringEnumRef](docs/StringEnumRef.md)
Expand Down
13 changes: 13 additions & 0 deletions samples/client/echo_api/java/apache-httpclient/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,19 @@ components:
allOf:
- $ref: '#/components/schemas/DataQuery_allOf'
- $ref: '#/components/schemas/Query'
NumberPropertiesOnly:
properties:
number:
type: number
float:
format: float
type: number
double:
format: double
maximum: 50.2
minimum: 0.8
type: number
type: object
test_form_integer_boolean_string_request:
properties:
integer_form:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@


# NumberPropertiesOnly


## Properties

| Name | Type | Description | Notes |
|------------ | ------------- | ------------- | -------------|
|**number** | **BigDecimal** | | [optional] |
|**_float** | **Float** | | [optional] |
|**_double** | **Double** | | [optional] |



Loading