Skip to content

Commit 07227d4

Browse files
authored
add support for union of strictfloat and strictint (#15124)
1 parent b409ceb commit 07227d4

File tree

38 files changed

+1530
-34
lines changed

38 files changed

+1530
-34
lines changed

bin/configs/python-nextgen-aiohttp.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ templateDir: modules/openapi-generator/src/main/resources/python-nextgen
55
library: asyncio
66
additionalProperties:
77
packageName: petstore_api
8-
floatStrictType: false
8+
mapNumberTo: float

bin/configs/python-nextgen.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ additionalProperties:
66
packageName: petstore_api
77
useOneOfDiscriminatorLookup: "true"
88
disallowAdditionalPropertiesIfNotPresent: false
9+
mapNumberTo: StrictFloat

docs/generators/python-nextgen.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ These options may be applied as additional-properties (cli) or configOptions (pl
2222
|dateFormat|date format for query parameters| |%Y-%m-%d|
2323
|datetimeFormat|datetime format for query parameters| |%Y-%m-%dT%H:%M:%S%z|
2424
|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|
25-
|floatStrictType|Use strict type for float, i.e. StrictFloat or confloat(strict=true, ...)| |true|
2625
|generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false|
2726
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
2827
|library|library template (sub-template) to use: asyncio, tornado (deprecated), urllib3| |urllib3|
28+
|mapNumberTo|Map number to Union[StrictFloat, StrictInt], StrictStr or float.| |Union[StrictFloat, StrictInt]|
2929
|packageName|python package name (convention: snake_case).| |openapi_client|
3030
|packageUrl|python package URL.| |null|
3131
|packageVersion|python package version.| |1.0.0|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonNextgenClientCodegen.java

+82-26
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,18 @@ public class PythonNextgenClientCodegen extends AbstractPythonCodegen implements
4747
public static final String PACKAGE_URL = "packageUrl";
4848
public static final String DEFAULT_LIBRARY = "urllib3";
4949
public static final String RECURSION_LIMIT = "recursionLimit";
50-
public static final String FLOAT_STRICT_TYPE = "floatStrictType";
5150
public static final String DATETIME_FORMAT = "datetimeFormat";
5251
public static final String DATE_FORMAT = "dateFormat";
52+
public static final String MAP_NUMBER_TO = "mapNumberTo";
5353

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

6363
protected Map<Character, String> regexModifiers;
6464

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

284-
if (additionalProperties.containsKey(FLOAT_STRICT_TYPE)) {
285-
setFloatStrictType(convertPropertyToBooleanAndWriteBack(FLOAT_STRICT_TYPE));
284+
if (additionalProperties.containsKey(MAP_NUMBER_TO)) {
285+
setMapNumberTo(String.valueOf(additionalProperties.get(MAP_NUMBER_TO)));
286286
}
287287

288288
if (additionalProperties.containsKey(DATETIME_FORMAT)) {
@@ -478,34 +478,59 @@ private String getPydanticType(CodegenParameter cp,
478478
} else if (cp.isNumber || cp.isFloat || cp.isDouble) {
479479
if (cp.hasValidation) {
480480
List<String> fieldCustomization = new ArrayList<>();
481+
List<String> intFieldCustomization = new ArrayList<>();
482+
481483
// e.g. confloat(ge=10, le=100, strict=True)
482484
if (cp.getMaximum() != null) {
483485
if (cp.getExclusiveMaximum()) {
484-
fieldCustomization.add("gt=" + cp.getMaximum());
486+
fieldCustomization.add("lt=" + cp.getMaximum());
487+
intFieldCustomization.add("lt=" + Math.ceil(Double.valueOf(cp.getMaximum()))); // e.g. < 7.59 becomes < 8
485488
} else {
486-
fieldCustomization.add("ge=" + cp.getMaximum());
489+
fieldCustomization.add("le=" + cp.getMaximum());
490+
intFieldCustomization.add("le=" + Math.floor(Double.valueOf(cp.getMaximum()))); // e.g. <= 7.59 becomes <= 7
487491
}
488492
}
489493
if (cp.getMinimum() != null) {
490494
if (cp.getExclusiveMinimum()) {
491-
fieldCustomization.add("lt=" + cp.getMinimum());
495+
fieldCustomization.add("gt=" + cp.getMinimum());
496+
intFieldCustomization.add("gt=" + Math.floor(Double.valueOf(cp.getMinimum()))); // e.g. > 7.59 becomes > 7
492497
} else {
493-
fieldCustomization.add("le=" + cp.getMinimum());
498+
fieldCustomization.add("ge=" + cp.getMinimum());
499+
intFieldCustomization.add("ge=" + Math.ceil(Double.valueOf(cp.getMinimum()))); // e.g. >= 7.59 becomes >= 8
494500
}
495501
}
496502
if (cp.getMultipleOf() != null) {
497503
fieldCustomization.add("multiple_of=" + cp.getMultipleOf());
498504
}
499505

500-
if (floatStrictType) {
506+
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
507+
fieldCustomization.add("strict=True");
508+
intFieldCustomization.add("strict=True");
509+
pydanticImports.add("confloat");
510+
pydanticImports.add("conint");
511+
typingImports.add("Union");
512+
return String.format(Locale.ROOT, "Union[%s(%s), %s(%s)]", "confloat",
513+
StringUtils.join(fieldCustomization, ", "),
514+
"conint",
515+
StringUtils.join(intFieldCustomization, ", ")
516+
);
517+
} else if ("StrictFloat".equals(mapNumberTo)) {
501518
fieldCustomization.add("strict=True");
519+
pydanticImports.add("confloat");
520+
return String.format(Locale.ROOT, "%s(%s)", "confloat",
521+
StringUtils.join(fieldCustomization, ", "));
522+
} else { // float
523+
pydanticImports.add("confloat");
524+
return String.format(Locale.ROOT, "%s(%s)", "confloat",
525+
StringUtils.join(fieldCustomization, ", "));
502526
}
503-
504-
pydanticImports.add("confloat");
505-
return String.format(Locale.ROOT, "%s(%s)", "confloat",
506-
StringUtils.join(fieldCustomization, ", "));
507527
} else {
508-
if (floatStrictType) {
528+
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
529+
typingImports.add("Union");
530+
pydanticImports.add("StrictFloat");
531+
pydanticImports.add("StrictInt");
532+
return "Union[StrictFloat, StrictInt]";
533+
} else if ("StrictFloat".equals(mapNumberTo)) {
509534
pydanticImports.add("StrictFloat");
510535
return "StrictFloat";
511536
} else {
@@ -723,34 +748,59 @@ private String getPydanticType(CodegenProperty cp,
723748
} else if (cp.isNumber || cp.isFloat || cp.isDouble) {
724749
if (cp.hasValidation) {
725750
List<String> fieldCustomization = new ArrayList<>();
751+
List<String> intFieldCustomization = new ArrayList<>();
752+
726753
// e.g. confloat(ge=10, le=100, strict=True)
727754
if (cp.getMaximum() != null) {
728755
if (cp.getExclusiveMaximum()) {
729756
fieldCustomization.add("lt=" + cp.getMaximum());
757+
intFieldCustomization.add("lt=" + (int) Math.ceil(Double.valueOf(cp.getMaximum()))); // e.g. < 7.59 => < 8
730758
} else {
731759
fieldCustomization.add("le=" + cp.getMaximum());
760+
intFieldCustomization.add("le=" + (int) Math.floor(Double.valueOf(cp.getMaximum()))); // e.g. <= 7.59 => <= 7
732761
}
733762
}
734763
if (cp.getMinimum() != null) {
735764
if (cp.getExclusiveMinimum()) {
736765
fieldCustomization.add("gt=" + cp.getMinimum());
766+
intFieldCustomization.add("gt=" + (int) Math.floor(Double.valueOf(cp.getMinimum()))); // e.g. > 7.59 => > 7
737767
} else {
738768
fieldCustomization.add("ge=" + cp.getMinimum());
769+
intFieldCustomization.add("ge=" + (int) Math.ceil(Double.valueOf(cp.getMinimum()))); // e.g. >= 7.59 => >= 8
739770
}
740771
}
741772
if (cp.getMultipleOf() != null) {
742773
fieldCustomization.add("multiple_of=" + cp.getMultipleOf());
743774
}
744775

745-
if (floatStrictType) {
776+
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
777+
fieldCustomization.add("strict=True");
778+
intFieldCustomization.add("strict=True");
779+
pydanticImports.add("confloat");
780+
pydanticImports.add("conint");
781+
typingImports.add("Union");
782+
return String.format(Locale.ROOT, "Union[%s(%s), %s(%s)]", "confloat",
783+
StringUtils.join(fieldCustomization, ", "),
784+
"conint",
785+
StringUtils.join(intFieldCustomization, ", ")
786+
);
787+
} else if ("StrictFloat".equals(mapNumberTo)) {
746788
fieldCustomization.add("strict=True");
789+
pydanticImports.add("confloat");
790+
return String.format(Locale.ROOT, "%s(%s)", "confloat",
791+
StringUtils.join(fieldCustomization, ", "));
792+
} else { // float
793+
pydanticImports.add("confloat");
794+
return String.format(Locale.ROOT, "%s(%s)", "confloat",
795+
StringUtils.join(fieldCustomization, ", "));
747796
}
748-
749-
pydanticImports.add("confloat");
750-
return String.format(Locale.ROOT, "%s(%s)", "confloat",
751-
StringUtils.join(fieldCustomization, ", "));
752797
} else {
753-
if (floatStrictType) {
798+
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)) {
799+
typingImports.add("Union");
800+
pydanticImports.add("StrictFloat");
801+
pydanticImports.add("StrictInt");
802+
return "Union[StrictFloat, StrictInt]";
803+
} else if ("StrictFloat".equals(mapNumberTo)) {
754804
pydanticImports.add("StrictFloat");
755805
return "StrictFloat";
756806
} else {
@@ -1334,8 +1384,8 @@ public void postProcessPattern(String pattern, Map<String, Object> vendorExtensi
13341384
}
13351385
}
13361386

1337-
vendorExtensions.put("x-regex", regex.replace("\"","\\\""));
1338-
vendorExtensions.put("x-pattern", pattern.replace("\"","\\\""));
1387+
vendorExtensions.put("x-regex", regex.replace("\"", "\\\""));
1388+
vendorExtensions.put("x-pattern", pattern.replace("\"", "\\\""));
13391389
vendorExtensions.put("x-modifiers", modifiers);
13401390
}
13411391
}
@@ -1529,8 +1579,14 @@ public String escapeReservedWord(String name) {
15291579
return "var_" + name;
15301580
}
15311581

1532-
public void setFloatStrictType(boolean floatStrictType) {
1533-
this.floatStrictType = floatStrictType;
1582+
public void setMapNumberTo(String mapNumberTo) {
1583+
if ("Union[StrictFloat, StrictInt]".equals(mapNumberTo)
1584+
|| "StrictFloat".equals(mapNumberTo)
1585+
|| "float".equals(mapNumberTo)) {
1586+
this.mapNumberTo = mapNumberTo;
1587+
} else {
1588+
throw new IllegalArgumentException("mapNumberTo value must be Union[StrictFloat, StrictInt], StrictStr or float");
1589+
}
15341590
}
15351591

15361592
public void setDatetimeFormat(String datetimeFormat) {

modules/openapi-generator/src/test/resources/3_0/echo_api.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,16 @@ components:
516516
format: date-time
517517
description: A date
518518
- $ref: '#/components/schemas/Query'
519+
NumberPropertiesOnly:
520+
type: object
521+
properties:
522+
number:
523+
type: number
524+
float:
525+
type: number
526+
format: float
527+
double:
528+
type: number
529+
format: double
530+
minimum: 0.8
531+
maximum: 50.2

samples/client/echo_api/java/apache-httpclient/.openapi-generator/FILES

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ docs/DataQueryAllOf.md
1313
docs/DefaultValue.md
1414
docs/FormApi.md
1515
docs/HeaderApi.md
16+
docs/NumberPropertiesOnly.md
1617
docs/PathApi.md
1718
docs/Pet.md
1819
docs/Query.md
@@ -53,6 +54,7 @@ src/main/java/org/openapitools/client/model/Category.java
5354
src/main/java/org/openapitools/client/model/DataQuery.java
5455
src/main/java/org/openapitools/client/model/DataQueryAllOf.java
5556
src/main/java/org/openapitools/client/model/DefaultValue.java
57+
src/main/java/org/openapitools/client/model/NumberPropertiesOnly.java
5658
src/main/java/org/openapitools/client/model/Pet.java
5759
src/main/java/org/openapitools/client/model/Query.java
5860
src/main/java/org/openapitools/client/model/StringEnumRef.java

samples/client/echo_api/java/apache-httpclient/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ Class | Method | HTTP request | Description
127127
- [DataQuery](docs/DataQuery.md)
128128
- [DataQueryAllOf](docs/DataQueryAllOf.md)
129129
- [DefaultValue](docs/DefaultValue.md)
130+
- [NumberPropertiesOnly](docs/NumberPropertiesOnly.md)
130131
- [Pet](docs/Pet.md)
131132
- [Query](docs/Query.md)
132133
- [StringEnumRef](docs/StringEnumRef.md)

samples/client/echo_api/java/apache-httpclient/api/openapi.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,19 @@ components:
521521
allOf:
522522
- $ref: '#/components/schemas/DataQuery_allOf'
523523
- $ref: '#/components/schemas/Query'
524+
NumberPropertiesOnly:
525+
properties:
526+
number:
527+
type: number
528+
float:
529+
format: float
530+
type: number
531+
double:
532+
format: double
533+
maximum: 50.2
534+
minimum: 0.8
535+
type: number
536+
type: object
524537
test_form_integer_boolean_string_request:
525538
properties:
526539
integer_form:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
3+
# NumberPropertiesOnly
4+
5+
6+
## Properties
7+
8+
| Name | Type | Description | Notes |
9+
|------------ | ------------- | ------------- | -------------|
10+
|**number** | **BigDecimal** | | [optional] |
11+
|**_float** | **Float** | | [optional] |
12+
|**_double** | **Double** | | [optional] |
13+
14+
15+

0 commit comments

Comments
 (0)