Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 0e72fc7

Browse files
committed
v2 Restructures endpoint parameter, body + response information (#57)
* Restructures endpoint data, modules written for responses * Endpoint docs improved, not done yet * Updates header_params * Updates path_parameters * Updates cookie_params, updates x_params to say key + input type * Samples updated * Fixes DefaultCodegenTests
1 parent cc828c9 commit 0e72fc7

File tree

1,407 files changed

+140390
-123022
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,407 files changed

+140390
-123022
lines changed

modules/openapi-json-schema-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties {
9393
private Map<String, CodegenProperty> requiredVarsMap;
9494
private String ref;
9595
private boolean schemaIsFromAdditionalProperties;
96+
public Set<String> imports = new TreeSet<>();
9697

9798
@Override
9899
public int hashCode() {
@@ -105,7 +106,7 @@ public int hashCode() {
105106
getMinLength(), exclusiveMinimum, exclusiveMaximum, getMinimum(), getMaximum(), getPattern(),
106107
is1xx, is2xx, is3xx, is4xx, is5xx, additionalPropertiesIsAnyType, hasVars, hasRequired,
107108
hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, responseHeaders, content,
108-
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties);
109+
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties, imports);
109110
}
110111

111112
@Override
@@ -155,6 +156,7 @@ public boolean equals(Object o) {
155156
getAdditionalPropertiesIsAnyType() == that.getAdditionalPropertiesIsAnyType() &&
156157
getHasVars() == that.getHasVars() &&
157158
getHasRequired() == that.getHasRequired() &&
159+
Objects.equals(imports, that.imports) &&
158160
Objects.equals(uniqueItemsBoolean, that.getUniqueItemsBoolean()) &&
159161
Objects.equals(ref, that.getRef()) &&
160162
Objects.equals(requiredVarsMap, that.getRequiredVarsMap()) &&
@@ -612,6 +614,7 @@ public String toString() {
612614
sb.append(", requiredVarsMap=").append(requiredVarsMap);
613615
sb.append(", ref=").append(ref);
614616
sb.append(", schemaIsFromAdditionalProperties=").append(schemaIsFromAdditionalProperties);
617+
sb.append(", imports=").append(imports);
615618
sb.append('}');
616619
return sb.toString();
617620
}

modules/openapi-json-schema-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4265,13 +4265,12 @@ public CodegenOperation fromOperation(String path,
42654265
for (Entry<String, Header> entry : headers.entrySet()) {
42664266
String headerName = entry.getKey();
42674267
Header header = ModelUtils.getReferencedHeader(this.openAPI, entry.getValue());
4268-
CodegenParameter responseHeader = headerToCodegenParameter(header, headerName, imports, String.format(Locale.ROOT, "%sResponseParameter", r.code));
4268+
CodegenParameter responseHeader = headerToCodegenParameter(header, headerName, r.imports, String.format(Locale.ROOT, "%sResponseParameter", r.code));
42694269
responseHeaders.add(responseHeader);
42704270
}
42714271
r.setResponseHeaders(responseHeaders);
42724272
}
4273-
String mediaTypeSchemaSuffix = String.format(Locale.ROOT, "%sResponseBody", r.code);
4274-
r.setContent(getContent(response.getContent(), imports, mediaTypeSchemaSuffix));
4273+
r.setContent(getContent(response.getContent(), r.imports, ""));
42754274

42764275
if (!addSchemaImportsFromV3SpecLocations) {
42774276
if (r.baseType != null &&
@@ -4391,7 +4390,7 @@ public CodegenOperation fromOperation(String path,
43914390
param = ModelUtils.getReferencedParameter(this.openAPI, param);
43924391

43934392
CodegenParameter p = fromParameter(param, imports);
4394-
p.setContent(getContent(param.getContent(), imports, "RequestParameter" + toModelName(param.getName())));
4393+
p.setContent(getContent(param.getContent(), imports, param.getName()));
43954394

43964395
// ensure unique params
43974396
if (ensureUniqueParams) {
@@ -7092,10 +7091,6 @@ protected void updateRequestBodyForString(CodegenParameter codegenParameter, Sch
70927091
codegenParameter.pattern = toRegularExpression(schema.getPattern());
70937092
}
70947093

7095-
protected String toMediaTypeSchemaName(String contentType, String mediaTypeSchemaSuffix) {
7096-
return "SchemaFor" + mediaTypeSchemaSuffix + toModelName(contentType);
7097-
}
7098-
70997094
private CodegenParameter headerToCodegenParameter(Header header, String headerName, Set<String> imports, String mediaTypeSchemaSuffix) {
71007095
if (header == null) {
71017096
return null;
@@ -7121,7 +7116,7 @@ private CodegenParameter headerToCodegenParameter(Header header, String headerNa
71217116
return param;
71227117
}
71237118

7124-
protected LinkedHashMap<String, CodegenMediaType> getContent(Content content, Set<String> imports, String mediaTypeSchemaSuffix) {
7119+
protected LinkedHashMap<String, CodegenMediaType> getContent(Content content, Set<String> imports, String schemaName) {
71257120
if (content == null) {
71267121
return null;
71277122
}
@@ -7140,7 +7135,7 @@ protected LinkedHashMap<String, CodegenMediaType> getContent(Content content, Se
71407135
for (Entry<String, Header> headerEntry : encHeaders.entrySet()) {
71417136
String headerName = headerEntry.getKey();
71427137
Header header = ModelUtils.getReferencedHeader(this.openAPI, headerEntry.getValue());
7143-
CodegenParameter param = headerToCodegenParameter(header, headerName, imports, mediaTypeSchemaSuffix);
7138+
CodegenParameter param = headerToCodegenParameter(header, headerName, imports, schemaName);
71447139
headers.add(param);
71457140
}
71467141
}
@@ -7157,8 +7152,12 @@ protected LinkedHashMap<String, CodegenMediaType> getContent(Content content, Se
71577152
}
71587153
String contentType = contentEntry.getKey();
71597154
CodegenProperty schemaProp = null;
7155+
String usedSchemaName = schemaName;
7156+
if (usedSchemaName.equals("")) {
7157+
usedSchemaName = contentType;
7158+
}
71607159
if (mt.getSchema() != null) {
7161-
schemaProp = fromProperty(toMediaTypeSchemaName(contentType, mediaTypeSchemaSuffix), mt.getSchema(), false);
7160+
schemaProp = fromProperty(usedSchemaName, mt.getSchema(), false);
71627161
}
71637162
HashMap<String, SchemaTestCase> schemaTestCases = null;
71647163
if (mt.getExtensions() != null && mt.getExtensions().containsKey(xSchemaTestExamplesKey)) {
@@ -7207,7 +7206,7 @@ public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, S
72077206
if (schema == null) {
72087207
throw new RuntimeException("Request body cannot be null. Possible cause: missing schema in body parameter (OAS v2): " + body);
72097208
}
7210-
codegenParameter.setContent(getContent(body.getContent(), imports, "RequestBody"));
7209+
codegenParameter.setContent(getContent(body.getContent(), imports, ""));
72117210

72127211
if (StringUtils.isNotBlank(schema.get$ref())) {
72137212
name = ModelUtils.getSimpleRef(schema.get$ref());

modules/openapi-json-schema-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java

Lines changed: 39 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,8 @@ protected void generateEndpoints(OperationsMap objs) {
552552
OperationMap operations = objs.getOperations();
553553
List<CodegenOperation> codegenOperations = operations.getOperation();
554554
HashMap<String, String> pathModuleToPath = new HashMap<>();
555-
// paths.some_path.post.py (single endpoint definition)
555+
// paths.some_path.post.__init__.py (single endpoint definition)
556+
// responses are adjacent to the init file
556557
for (CodegenOperation co: codegenOperations) {
557558
if (co.tags != null) {
558559
for (Tag tag: co.tags) {
@@ -574,14 +575,29 @@ protected void generateEndpoints(OperationsMap objs) {
574575
endpointMap.put("operation", co);
575576
endpointMap.put("imports", co.imports);
576577
endpointMap.put("packageName", packageName);
577-
outputFilename = packageFilename(Arrays.asList("paths", pathModuleName, co.httpMethod + ".py"));
578+
outputFilename = packageFilename(Arrays.asList("paths", pathModuleName, co.httpMethod, "__init__.py"));
578579
pathsFiles.add(Arrays.asList(endpointMap, "endpoint.handlebars", outputFilename));
580+
581+
for (CodegenResponse response: co.responses) {
582+
// paths.some_path.post.response_for_200.py (file per response)
583+
Map<String, Object> responseMap = new HashMap<>();
584+
responseMap.put("response", response);
585+
responseMap.put("packageName", packageName);
586+
String responseModuleName = "response_for_";
587+
if (response.isDefault) {
588+
responseModuleName += "default";
589+
} else {
590+
responseModuleName += response.code;
591+
}
592+
String responseFilename = packageFilename(Arrays.asList("paths", pathModuleName, co.httpMethod, responseModuleName+ ".py"));
593+
pathsFiles.add(Arrays.asList(responseMap, "endpoint_response.handlebars", responseFilename));
594+
}
579595
/*
580596
This stub file exists to allow pycharm to read and use typing.overload decorators for it to see that
581597
dict_instance["someProp"] is of type SomeClass.properties.someProp
582598
See https://youtrack.jetbrains.com/issue/PY-42137/PyCharm-type-hinting-doesnt-work-well-with-overload-decorator
583599
*/
584-
String stubOutputFilename = packageFilename(Arrays.asList("paths", pathModuleName, co.httpMethod + ".pyi"));
600+
String stubOutputFilename = packageFilename(Arrays.asList("paths", pathModuleName, co.httpMethod, "__init__.pyi"));
585601
pathsFiles.add(Arrays.asList(endpointMap, "endpoint_stub.handlebars", stubOutputFilename));
586602

587603
Map<String, Object> endpointTestMap = new HashMap<>();
@@ -749,72 +765,7 @@ public String getHelp() {
749765

750766
@Override
751767
public Schema unaliasSchema(Schema schema) {
752-
Map<String, Schema> allSchemas = ModelUtils.getSchemas(openAPI);
753-
if (allSchemas == null || allSchemas.isEmpty()) {
754-
// skip the warning as the spec can have no model defined
755-
//LOGGER.warn("allSchemas cannot be null/empty in unaliasSchema. Returned 'schema'");
756-
return schema;
757-
}
758-
759-
if (schema != null && StringUtils.isNotEmpty(schema.get$ref())) {
760-
String simpleRef = ModelUtils.getSimpleRef(schema.get$ref());
761-
if (schemaMapping.containsKey(simpleRef)) {
762-
LOGGER.debug("Schema unaliasing of {} omitted because aliased class is to be mapped to {}", simpleRef, schemaMapping.get(simpleRef));
763-
return schema;
764-
}
765-
Schema ref = allSchemas.get(simpleRef);
766-
if (ref == null) {
767-
once(LOGGER).warn("{} is not defined", schema.get$ref());
768-
return schema;
769-
} else if (ref.getEnum() != null && !ref.getEnum().isEmpty()) {
770-
// top-level enum class
771-
return schema;
772-
} else if (ModelUtils.isArraySchema(ref)) {
773-
if (ModelUtils.isGenerateAliasAsModel(ref)) {
774-
return schema; // generate a model extending array
775-
} else {
776-
return unaliasSchema(allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
777-
}
778-
} else if (ModelUtils.isComposedSchema(ref)) {
779-
return schema;
780-
} else if (ModelUtils.isMapSchema(ref)) {
781-
if (ref.getProperties() != null && !ref.getProperties().isEmpty()) // has at least one property
782-
return schema; // treat it as model
783-
else {
784-
if (ModelUtils.isGenerateAliasAsModel(ref)) {
785-
return schema; // generate a model extending map
786-
} else {
787-
// treat it as a typical map
788-
return unaliasSchema(allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
789-
}
790-
}
791-
} else if (ModelUtils.isObjectSchema(ref)) { // model
792-
if (ref.getProperties() != null && !ref.getProperties().isEmpty()) { // has at least one property
793-
return schema;
794-
} else {
795-
// free form object (type: object)
796-
if (ModelUtils.hasValidation(ref)) {
797-
return schema;
798-
} else if (getAllOfDescendants(simpleRef, openAPI).size() > 0) {
799-
return schema;
800-
}
801-
return unaliasSchema(allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
802-
}
803-
} else if (ModelUtils.hasValidation(ref)) {
804-
// non object non array non map schemas that have validations
805-
// are returned so we can generate those schemas as models
806-
// we do this to:
807-
// - preserve the validations in that model class in python
808-
// - use those validations when we use this schema in composed oneOf schemas
809-
return schema;
810-
} else if (Boolean.TRUE.equals(ref.getNullable()) && ref.getEnum() == null) {
811-
// non enum primitive with nullable True
812-
// we make these models so instances of this will be subclasses of this model
813-
return schema;
814-
} else {
815-
return unaliasSchema(allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
816-
}
817-
}
768+
// python allows schemas to be inlined at any location so unaliasing should do nothing
818769
return schema;
819770
}
820771

@@ -892,6 +843,17 @@ public String toModelImport(String name) {
892843
return "from " + packagePath() + "." + modelPackage() + "." + toModelFilename(name) + " import " + toModelName(name);
893844
}
894845

846+
private void fixSchemaImports(Set<String> imports) {
847+
if (imports.size() == 0) {
848+
return;
849+
}
850+
String[] modelNames = imports.toArray(new String[0]);
851+
imports.clear();
852+
for (String modelName : modelNames) {
853+
imports.add(toModelImport(modelName));
854+
}
855+
}
856+
895857
@Override
896858
@SuppressWarnings("static-method")
897859
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
@@ -902,13 +864,9 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
902864
OperationMap val = objs.getOperations();
903865
List<CodegenOperation> operations = val.getOperation();
904866
for (CodegenOperation operation : operations) {
905-
if (operation.imports.size() == 0) {
906-
continue;
907-
}
908-
String[] modelNames = operation.imports.toArray(new String[0]);
909-
operation.imports.clear();
910-
for (String modelName : modelNames) {
911-
operation.imports.add(toModelImport(modelName));
867+
fixSchemaImports(operation.imports);
868+
for (CodegenResponse response: operation.responses) {
869+
fixSchemaImports(response.imports);
912870
}
913871
}
914872
generateEndpoints(objs);
@@ -996,18 +954,6 @@ public CodegenParameter fromParameter(Parameter parameter, Set<String> imports)
996954
break;
997955
}
998956
}
999-
// clone this so we can change some properties on it
1000-
CodegenProperty schemaProp = cp.getSchema();
1001-
// parameters may have valid python names like some_val or invalid ones like Content-Type
1002-
// we always set nameInSnakeCase to null so special handling will not be done for these names
1003-
// invalid python names will be handled in python by using a TypedDict which will allow us to have a type hint
1004-
// for keys that cannot be variable names to the schema baseName
1005-
if (schemaProp != null) {
1006-
schemaProp = schemaProp.clone();
1007-
schemaProp.nameInSnakeCase = null;
1008-
schemaProp.baseName = toModelName(cp.baseName) + "Schema";
1009-
cp.setSchema(schemaProp);
1010-
}
1011957
return cp;
1012958
}
1013959

@@ -2661,13 +2607,17 @@ public List<CodegenParameter> fromRequestBodyToFormParameters(RequestBody body,
26612607
Schema schema = ModelUtils.getSchemaFromRequestBody(body);
26622608
schema = ModelUtils.getReferencedSchema(this.openAPI, schema);
26632609
CodegenParameter cp = fromFormProperty("body", schema, imports);
2664-
cp.setContent(getContent(body.getContent(), imports, "RequestBody"));
2610+
cp.setContent(getContent(body.getContent(), imports, ""));
26652611
cp.isFormParam = false;
26662612
cp.isBodyParam = true;
26672613
parameters.add(cp);
26682614
return parameters;
26692615
}
26702616

2617+
protected boolean needToImport(String type) {
2618+
return true;
2619+
}
2620+
26712621
/**
26722622
* Custom version of this method so we can move the body parameter into bodyParam
26732623
*

modules/openapi-json-schema-generator/src/main/resources/python/api_client.handlebars

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# coding: utf-8
22
{{>partial_header}}
33

4-
from dataclasses import dataclass
4+
import dataclasses
55
from decimal import Decimal
66
import enum
77
import email
@@ -339,7 +339,7 @@ class JSONDetector:
339339
return False
340340

341341

342-
@dataclass
342+
@dataclasses.dataclass
343343
class ParameterBase(JSONDetector):
344344
name: str
345345
in_type: ParameterInType
@@ -779,7 +779,7 @@ class Encoding:
779779
self.allow_reserved = allow_reserved
780780

781781

782-
@dataclass
782+
@dataclasses.dataclass
783783
class MediaType:
784784
"""
785785
Used to store request and response body schema information
@@ -793,7 +793,7 @@ class MediaType:
793793
encoding: typing.Optional[typing.Dict[str, Encoding]] = None
794794

795795

796-
@dataclass
796+
@dataclasses.dataclass
797797
class ApiResponse:
798798
response: urllib3.HTTPResponse
799799
body: typing.Union[Unset, Schema]
@@ -802,8 +802,8 @@ class ApiResponse:
802802
def __init__(
803803
self,
804804
response: urllib3.HTTPResponse,
805-
body: typing.Union[Unset, typing.Type[Schema]],
806-
headers: typing.Union[Unset, typing.List[HeaderParameter]]
805+
body: typing.Union[Unset, typing.Type[Schema]] = unset,
806+
headers: typing.Union[Unset, typing.List[HeaderParameter]] = unset
807807
):
808808
"""
809809
pycharm needs this to prevent 'Unexpected argument' warnings
@@ -813,7 +813,7 @@ class ApiResponse:
813813
self.headers = headers
814814

815815

816-
@dataclass
816+
@dataclasses.dataclass
817817
class ApiResponseWithoutDeserialization(ApiResponse):
818818
response: urllib3.HTTPResponse
819819
body: typing.Union[Unset, typing.Type[Schema]] = unset

0 commit comments

Comments
 (0)