diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java index f7b7202d543a..fde192bcac67 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java @@ -655,9 +655,124 @@ private List> toPyImports(CodegenModel cm, Set impor return pyImports; } + @Override + public String toDefaultValue(Schema p) { + Schema unaliased = p != null ? ModelUtils.unaliasSchema(this.openAPI, p) : null; + Object rawDefault = p != null && p.getDefault() != null ? p.getDefault() + : (unaliased != null ? unaliased.getDefault() : null); + Schema target = unaliased != null ? unaliased : p; + if (target != null && ModelUtils.isArraySchema(target) && rawDefault instanceof Iterable) { + return formatPythonDefaultValue(rawDefault, target); + } + return super.toDefaultValue(p); + } + + private String formatPythonDefaultValue(Object value, Schema schema) { + Schema target = schema != null ? ModelUtils.unaliasSchema(this.openAPI, schema) : null; + if (value == null || (value instanceof com.fasterxml.jackson.databind.JsonNode + && ((com.fasterxml.jackson.databind.JsonNode) value).isNull())) { + return "None"; + } + if (value instanceof com.fasterxml.jackson.databind.JsonNode) { + com.fasterxml.jackson.databind.JsonNode node = (com.fasterxml.jackson.databind.JsonNode) value; + if (node.isArray()) { + Schema itemSchema = target != null ? ModelUtils.getSchemaItems(target) : null; + List elements = new ArrayList<>(); + for (com.fasterxml.jackson.databind.JsonNode elem : node) { + elements.add(formatPythonDefaultValue(elem, itemSchema)); + } + return "[" + String.join(", ", elements) + "]"; + } + if (node.isObject()) { + List entries = new ArrayList<>(); + Iterator> fields = node.fields(); + while (fields.hasNext()) { + Map.Entry entry = fields.next(); + Schema propSchema = null; + if (target != null && target.getProperties() != null) { + propSchema = (Schema) target.getProperties().get(entry.getKey()); + } else if (target != null && ModelUtils.getAdditionalProperties(target) != null) { + propSchema = ModelUtils.getAdditionalProperties(target); + } + entries.add(formatPythonStringLiteral(entry.getKey()) + ": " + + formatPythonDefaultValue(entry.getValue(), propSchema)); + } + return "{" + String.join(", ", entries) + "}"; + } + if (node.isBoolean() || (target != null && ModelUtils.isBooleanSchema(target))) { + return node.asBoolean() ? "True" : "False"; + } + if (node.isNumber() || (target != null && (ModelUtils.isIntegerSchema(target) || ModelUtils.isNumberSchema(target)))) { + return node.asText(); + } + return formatPythonStringLiteral(node.asText()); + } + if (value instanceof Iterable) { + Schema itemSchema = target != null ? ModelUtils.getSchemaItems(target) : null; + List elements = new ArrayList<>(); + for (Object elem : (Iterable) value) { + elements.add(formatPythonDefaultValue(elem, itemSchema)); + } + return "[" + String.join(", ", elements) + "]"; + } + if (value instanceof Map) { + List entries = new ArrayList<>(); + for (Map.Entry entry : ((Map) value).entrySet()) { + String key = String.valueOf(entry.getKey()); + Schema propSchema = null; + if (target != null && target.getProperties() != null) { + propSchema = (Schema) target.getProperties().get(key); + } else if (target != null && ModelUtils.getAdditionalProperties(target) != null) { + propSchema = ModelUtils.getAdditionalProperties(target); + } + entries.add(formatPythonStringLiteral(key) + ": " + + formatPythonDefaultValue(entry.getValue(), propSchema)); + } + return "{" + String.join(", ", entries) + "}"; + } + if (value instanceof Boolean || (target != null && ModelUtils.isBooleanSchema(target))) { + return Boolean.parseBoolean(value.toString()) ? "True" : "False"; + } + if (value instanceof Number || (target != null && (ModelUtils.isIntegerSchema(target) || ModelUtils.isNumberSchema(target)))) { + return value.toString(); + } + return formatPythonStringLiteral(value.toString()); + } + @Override public void postProcessParameter(CodegenParameter parameter) { postProcessPattern(parameter.pattern, parameter.vendorExtensions); + Object openapiName = parameter.vendorExtensions.get("x-python-connexion-openapi-name"); + if (openapiName instanceof String) { + parameter.baseName = (String) openapiName; + } + if (parameter.isHeaderParam || parameter.isCookieParam) { + boolean isJsonContent = parameter.headerIsJsonMimeType + || isJsonMimeType(parameter.contentType) + || isJsonVendorMimeType(parameter.contentType); + if (isJsonContent) { + parameter.vendorExtensions.put("x-python-connexion-json-content", Boolean.TRUE); + } else if (parameter.isArray) { + if (parameter.items == null || !parameter.items.isModel) { + parameter.vendorExtensions.put("x-python-connexion-split-csv", Boolean.TRUE); + } + if (parameter.items != null) { + if (parameter.items.isInteger || parameter.items.isLong) { + parameter.vendorExtensions.put("x-python-connexion-cast-int-items", Boolean.TRUE); + } else if (parameter.items.isNumber || parameter.items.isFloat || parameter.items.isDouble) { + parameter.vendorExtensions.put("x-python-connexion-cast-float-items", Boolean.TRUE); + } else if (parameter.items.isBoolean) { + parameter.vendorExtensions.put("x-python-connexion-cast-bool-items", Boolean.TRUE); + } + } + } else if (parameter.isInteger || parameter.isLong) { + parameter.vendorExtensions.put("x-python-connexion-cast-int", Boolean.TRUE); + } else if (parameter.isNumber || parameter.isFloat || parameter.isDouble) { + parameter.vendorExtensions.put("x-python-connexion-cast-float", Boolean.TRUE); + } else if (parameter.isBoolean) { + parameter.vendorExtensions.put("x-python-connexion-cast-bool", Boolean.TRUE); + } + } } @Override @@ -665,7 +780,18 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List operationList = operations.getOperation(); + boolean hasJsonHeaderParam = false; for (CodegenOperation operation : operationList) { + List handlerParams = new ArrayList<>(); + for (CodegenParameter param : operation.allParams) { + if (!param.isHeaderParam && !param.isCookieParam) { + handlerParams.add(param); + } + if (Boolean.TRUE.equals(param.vendorExtensions.get("x-python-connexion-json-content"))) { + hasJsonHeaderParam = true; + } + } + operation.vendorExtensions.put("x-handler-params", handlerParams); Map skipTests = new HashMap<>(); // Set flag to deactivate tests due to connexion issue. if (operation.consumes != null) { @@ -725,6 +851,9 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List web.Response: +async def {{operationId}}(request: web.Request, {{#vendorExtensions.x-handler-params}}{{paramName}}{{^required}}=None{{/required}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-handler-params}}) -> web.Response: """{{summary}}{{^summary}}{{operationId}}{{/summary}} {{notes}} @@ -57,17 +60,63 @@ async def {{operationId}}(request: web.Request, {{#allParams}}{{paramName}}{{^re """ {{#allParams}} + {{#isHeaderParam}} + {{paramName}} = request.headers.get('{{baseName}}'{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}) + {{/isHeaderParam}} + {{#isCookieParam}} + {{paramName}} = request.cookies.get('{{baseName}}'{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}) + {{/isCookieParam}} + {{#vendorExtensions.x-python-connexion-cast-int}} + if {{paramName}} is not None: + {{paramName}} = int({{paramName}}) + {{/vendorExtensions.x-python-connexion-cast-int}} + {{#vendorExtensions.x-python-connexion-cast-float}} + if {{paramName}} is not None: + {{paramName}} = float({{paramName}}) + {{/vendorExtensions.x-python-connexion-cast-float}} + {{#vendorExtensions.x-python-connexion-cast-bool}} + if isinstance({{paramName}}, str): + {{paramName}} = {{paramName}}.lower() == 'true' + {{/vendorExtensions.x-python-connexion-cast-bool}} + {{#vendorExtensions.x-python-connexion-json-content}} + if isinstance({{paramName}}, str): + {{paramName}} = json.loads({{paramName}}) + {{/vendorExtensions.x-python-connexion-json-content}} + {{#vendorExtensions.x-python-connexion-split-csv}} + if isinstance({{paramName}}, str): + {{paramName}} = {{paramName}}.split(',') + {{/vendorExtensions.x-python-connexion-split-csv}} + {{#vendorExtensions.x-python-connexion-cast-int-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [int(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-int-items}} + {{#vendorExtensions.x-python-connexion-cast-float-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [float(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-float-items}} + {{#vendorExtensions.x-python-connexion-cast-bool-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [x.lower() == 'true' if isinstance(x, str) else bool(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-bool-items}} {{^isContainer}} {{#isDate}} - {{paramName}} = util.deserialize_date({{paramName}}) + if {{paramName}} is not None: + {{paramName}} = util.deserialize_date({{paramName}}) {{/isDate}} {{#isDateTime}} - {{paramName}} = util.deserialize_datetime({{paramName}}) + if {{paramName}} is not None: + {{paramName}} = util.deserialize_datetime({{paramName}}) {{/isDateTime}} {{^isPrimitiveType}} {{^isFile}} {{^isUuid}} + {{#isBodyParam}} {{paramName}} = {{baseType}}.from_dict({{paramName}}) + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {{baseType}}{{^baseType}}{{#dataType}}{{.}}{{/dataType}}{{/baseType}}.from_dict({{paramName}}) + {{/isBodyParam}} {{/isUuid}} {{/isFile}} {{/isPrimitiveType}} @@ -75,13 +124,31 @@ async def {{operationId}}(request: web.Request, {{#allParams}}{{paramName}}{{^re {{#isArray}} {{#items}} {{#isDate}} + {{#isBodyParam}} {{paramName}} = [util.deserialize_date(s) for s in {{paramName}}] + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [util.deserialize_date(s) for s in {{paramName}}] + {{/isBodyParam}} {{/isDate}} {{#isDateTime}} + {{#isBodyParam}} {{paramName}} = [util.deserialize_datetime(s) for s in {{paramName}}] + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [util.deserialize_datetime(s) for s in {{paramName}}] + {{/isBodyParam}} {{/isDateTime}} {{#complexType}} + {{#isBodyParam}} {{paramName}} = [{{complexType}}.from_dict(d) for d in {{paramName}}] + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [{{complexType}}.from_dict(d) for d in {{paramName}}] + {{/isBodyParam}} {{/complexType}} {{/items}} {{/isArray}} diff --git a/modules/openapi-generator/src/main/resources/python-aiohttp/controller_test.mustache b/modules/openapi-generator/src/main/resources/python-aiohttp/controller_test.mustache index 383c0bf9dfa3..7b7bb817431e 100644 --- a/modules/openapi-generator/src/main/resources/python-aiohttp/controller_test.mustache +++ b/modules/openapi-generator/src/main/resources/python-aiohttp/controller_test.mustache @@ -36,7 +36,7 @@ async def test_{{operationId}}(client): headers = { {{#vendorExtensions.x-preferred-produce}} 'Accept': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-produce}}{{#vendorExtensions.x-preferred-consume}} 'Content-Type': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-consume}}{{#headerParams}} - '{{paramName}}': {{{example}}},{{/headerParams}}{{#authMethods}} + '{{baseName}}': {{{example}}},{{/headerParams}}{{#authMethods}} {{#isOAuth}}'Authorization': 'Bearer special-key',{{/isOAuth}}{{#isApiKey}}'{{name}}': 'special-key',{{/isApiKey}}{{#isBasicBasic}}'Authorization': 'BasicZm9vOmJhcg==',{{/isBasicBasic}}{{#isBasicBearer}}'Authorization': 'Bearer special-key',{{/isBasicBearer}}{{/authMethods}} } {{#formParams}} diff --git a/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/controllers/controller.mustache b/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/controllers/controller.mustache index afba1f7cfefb..8c116a15c70a 100644 --- a/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/controllers/controller.mustache +++ b/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/controllers/controller.mustache @@ -1,4 +1,7 @@ import connexion +{{#hasJsonHeaderParam}} +import json +{{/hasJsonHeaderParam}} {{#imports}}{{import}} # noqa: E501 {{/imports}} @@ -7,7 +10,7 @@ from {{packageName}} import util {{#operation}} -def {{operationId}}({{#allParams}}{{paramName}}{{^required}}=None{{/required}}{{^-last}}, {{/-last}}{{/allParams}}): # noqa: E501 +def {{operationId}}({{#vendorExtensions.x-handler-params}}{{paramName}}{{^required}}=None{{/required}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-handler-params}}): # noqa: E501 """{{summary}}{{^summary}}{{operationId}}{{/summary}} {{notes}} # noqa: E501 @@ -57,18 +60,64 @@ def {{operationId}}({{#allParams}}{{paramName}}{{^required}}=None{{/required}}{{ :rtype: {{returnType}}{{^returnType}}None{{/returnType}} """ {{#allParams}} + {{#isHeaderParam}} + {{paramName}} = connexion.request.headers.get('{{baseName}}'{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}) + {{/isHeaderParam}} + {{#isCookieParam}} + {{paramName}} = connexion.request.cookies.get('{{baseName}}'{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}) + {{/isCookieParam}} + {{#vendorExtensions.x-python-connexion-cast-int}} + if {{paramName}} is not None: + {{paramName}} = int({{paramName}}) + {{/vendorExtensions.x-python-connexion-cast-int}} + {{#vendorExtensions.x-python-connexion-cast-float}} + if {{paramName}} is not None: + {{paramName}} = float({{paramName}}) + {{/vendorExtensions.x-python-connexion-cast-float}} + {{#vendorExtensions.x-python-connexion-cast-bool}} + if isinstance({{paramName}}, str): + {{paramName}} = {{paramName}}.lower() == 'true' + {{/vendorExtensions.x-python-connexion-cast-bool}} + {{#vendorExtensions.x-python-connexion-json-content}} + if isinstance({{paramName}}, str): + {{paramName}} = json.loads({{paramName}}) + {{/vendorExtensions.x-python-connexion-json-content}} + {{#vendorExtensions.x-python-connexion-split-csv}} + if isinstance({{paramName}}, str): + {{paramName}} = {{paramName}}.split(',') + {{/vendorExtensions.x-python-connexion-split-csv}} + {{#vendorExtensions.x-python-connexion-cast-int-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [int(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-int-items}} + {{#vendorExtensions.x-python-connexion-cast-float-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [float(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-float-items}} + {{#vendorExtensions.x-python-connexion-cast-bool-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [x.lower() == 'true' if isinstance(x, str) else bool(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-bool-items}} {{^isContainer}} {{#isDate}} - {{paramName}} = util.deserialize_date({{paramName}}) + if {{paramName}} is not None: + {{paramName}} = util.deserialize_date({{paramName}}) {{/isDate}} {{#isDateTime}} - {{paramName}} = util.deserialize_datetime({{paramName}}) + if {{paramName}} is not None: + {{paramName}} = util.deserialize_datetime({{paramName}}) {{/isDateTime}} {{^isPrimitiveType}} {{^isFile}} {{^isUuid}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = {{baseType}}.from_dict(connexion.request.get_json()) # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {{baseType}}{{^baseType}}{{#dataType}}{{.}}{{/dataType}}{{/baseType}}.from_dict({{paramName}}) # noqa: E501 + {{/isBodyParam}} {{/isUuid}} {{/isFile}} {{/isPrimitiveType}} @@ -76,32 +125,68 @@ def {{operationId}}({{#allParams}}{{paramName}}{{^required}}=None{{/required}}{{ {{#isArray}} {{#items}} {{#isDate}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = [util.deserialize_date(s) for s in connexion.request.get_json()] # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [util.deserialize_date(s) for s in {{paramName}}] # noqa: E501 + {{/isBodyParam}} {{/isDate}} {{#isDateTime}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = [util.deserialize_datetime(s) for s in connexion.request.get_json()] # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [util.deserialize_datetime(s) for s in {{paramName}}] # noqa: E501 + {{/isBodyParam}} {{/isDateTime}} {{#complexType}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = [{{complexType}}.from_dict(d) for d in connexion.request.get_json()] # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [{{complexType}}.from_dict(d) for d in {{paramName}}] # noqa: E501 + {{/isBodyParam}} {{/complexType}} {{/items}} {{/isArray}} {{#isMap}} {{#items}} {{#isDate}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = {k: util.deserialize_date(v) for k, v in connexion.request.get_json().items()} # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {k: util.deserialize_date(v) for k, v in {{paramName}}.items()} # noqa: E501 + {{/isBodyParam}} {{/isDate}} {{#isDateTime}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = {k: util.deserialize_datetime(v) for k, v in connexion.request.get_json().items()} # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {k: util.deserialize_datetime(v) for k, v in {{paramName}}.items()} # noqa: E501 + {{/isBodyParam}} {{/isDateTime}} {{#complexType}} + {{#isBodyParam}} if connexion.request.is_json: {{paramName}} = {k: {{baseType}}.from_dict(v) for k, v in connexion.request.get_json().items()} # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {k: {{baseType}}.from_dict(v) for k, v in {{paramName}}.items()} # noqa: E501 + {{/isBodyParam}} {{/complexType}} {{/items}} {{/isMap}} diff --git a/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/test/controller_test.mustache b/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/test/controller_test.mustache index b9a5ea4eb95a..eb2ff317053e 100644 --- a/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/test/controller_test.mustache +++ b/modules/openapi-generator/src/main/resources/python-blueplanet/app/{{packageName}}/test/controller_test.mustache @@ -26,7 +26,7 @@ class {{#operations}}Test{{classname}}(BaseTestCase): {{#-first}}query_string = [{{/-first}}{{^-first}} {{/-first}}('{{paramName}}', {{{example}}}){{^-last}},{{/-last}}{{#-last}}]{{/-last}} {{/queryParams}} {{#headerParams}} - {{#-first}}headers = [{{/-first}}{{^-first}} {{/-first}}('{{paramName}}', {{{example}}}){{^-last}},{{/-last}}{{#-last}}]{{/-last}} + {{#-first}}headers = [{{/-first}}{{^-first}} {{/-first}}('{{baseName}}', {{{example}}}){{^-last}},{{/-last}}{{#-last}}]{{/-last}} {{/headerParams}} {{#formParams}} {{#-first}}data = dict({{/-first}}{{^-first}} {{/-first}}{{paramName}}={{{example}}}{{^-last}},{{/-last}}{{#-last}}){{/-last}} diff --git a/modules/openapi-generator/src/main/resources/python-flask/controller.mustache b/modules/openapi-generator/src/main/resources/python-flask/controller.mustache index d5118c610a74..552f6de7a3af 100644 --- a/modules/openapi-generator/src/main/resources/python-flask/controller.mustache +++ b/modules/openapi-generator/src/main/resources/python-flask/controller.mustache @@ -1,4 +1,7 @@ import flask +{{#hasJsonHeaderParam}} +import json +{{/hasJsonHeaderParam}} from typing import Dict from typing import Tuple from typing import Union @@ -10,7 +13,7 @@ from {{packageName}} import util {{#operation}} -def {{operationId}}({{#allParams}}{{^isBodyParam}}{{paramName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}{{^required}}=None{{/required}}{{^-last}}, {{/-last}}{{/allParams}}): # noqa: E501 +def {{operationId}}({{#vendorExtensions.x-handler-params}}{{^isBodyParam}}{{paramName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}{{^required}}=None{{/required}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-handler-params}}): # noqa: E501 """{{summary}}{{^summary}}{{operationId}}{{/summary}} {{notes}} # noqa: E501 @@ -60,21 +63,67 @@ def {{operationId}}({{#allParams}}{{^isBodyParam}}{{paramName}}{{/isBodyParam}}{ :rtype: Union[{{returnType}}{{^returnType}}None{{/returnType}}, Tuple[{{returnType}}{{^returnType}}None{{/returnType}}, int], Tuple[{{returnType}}{{^returnType}}None{{/returnType}}, int, Dict[str, str]] """ {{#allParams}} + {{#isHeaderParam}} + {{paramName}} = flask.request.headers.get('{{baseName}}'{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}) + {{/isHeaderParam}} + {{#isCookieParam}} + {{paramName}} = flask.request.cookies.get('{{baseName}}'{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}) + {{/isCookieParam}} + {{#vendorExtensions.x-python-connexion-cast-int}} + if {{paramName}} is not None: + {{paramName}} = int({{paramName}}) + {{/vendorExtensions.x-python-connexion-cast-int}} + {{#vendorExtensions.x-python-connexion-cast-float}} + if {{paramName}} is not None: + {{paramName}} = float({{paramName}}) + {{/vendorExtensions.x-python-connexion-cast-float}} + {{#vendorExtensions.x-python-connexion-cast-bool}} + if isinstance({{paramName}}, str): + {{paramName}} = {{paramName}}.lower() == 'true' + {{/vendorExtensions.x-python-connexion-cast-bool}} + {{#vendorExtensions.x-python-connexion-json-content}} + if isinstance({{paramName}}, str): + {{paramName}} = json.loads({{paramName}}) + {{/vendorExtensions.x-python-connexion-json-content}} + {{#vendorExtensions.x-python-connexion-split-csv}} + if isinstance({{paramName}}, str): + {{paramName}} = {{paramName}}.split(',') + {{/vendorExtensions.x-python-connexion-split-csv}} + {{#vendorExtensions.x-python-connexion-cast-int-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [int(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-int-items}} + {{#vendorExtensions.x-python-connexion-cast-float-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [float(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-float-items}} + {{#vendorExtensions.x-python-connexion-cast-bool-items}} + if isinstance({{paramName}}, list): + {{paramName}} = [x.lower() == 'true' if isinstance(x, str) else bool(x) for x in {{paramName}}] + {{/vendorExtensions.x-python-connexion-cast-bool-items}} {{#isBodyParam}} {{paramName}} = body {{/isBodyParam}} {{^isContainer}} {{#isDate}} - {{paramName}} = util.deserialize_date({{paramName}}) + if {{paramName}} is not None: + {{paramName}} = util.deserialize_date({{paramName}}) {{/isDate}} {{#isDateTime}} - {{paramName}} = util.deserialize_datetime({{paramName}}) + if {{paramName}} is not None: + {{paramName}} = util.deserialize_datetime({{paramName}}) {{/isDateTime}} {{^isPrimitiveType}} {{^isFile}} {{^isUuid}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = {{baseType}}{{^baseType}}{{#dataType}} {{.}}{{/dataType}}{{/baseType}}.from_dict(flask.request.get_json()) # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {{baseType}}{{^baseType}}{{#dataType}}{{.}}{{/dataType}}{{/baseType}}.from_dict({{paramName}}) # noqa: E501 + {{/isBodyParam}} {{/isUuid}} {{/isFile}} {{/isPrimitiveType}} @@ -82,32 +131,68 @@ def {{operationId}}({{#allParams}}{{^isBodyParam}}{{paramName}}{{/isBodyParam}}{ {{#isArray}} {{#items}} {{#isDate}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = [util.deserialize_date(s) for s in flask.request.get_json()] # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [util.deserialize_date(s) for s in {{paramName}}] # noqa: E501 + {{/isBodyParam}} {{/isDate}} {{#isDateTime}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = [util.deserialize_datetime(s) for s in flask.request.get_json()] # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [util.deserialize_datetime(s) for s in {{paramName}}] # noqa: E501 + {{/isBodyParam}} {{/isDateTime}} {{#complexType}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = [{{complexType}}.from_dict(d) for d in flask.request.get_json()] # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, list): + {{paramName}} = [{{complexType}}.from_dict(d) for d in {{paramName}}] # noqa: E501 + {{/isBodyParam}} {{/complexType}} {{/items}} {{/isArray}} {{#isMap}} {{#items}} {{#isDate}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = {k: util.deserialize_date(v) for k, v in flask.request.get_json().items()} # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {k: util.deserialize_date(v) for k, v in {{paramName}}.items()} # noqa: E501 + {{/isBodyParam}} {{/isDate}} {{#isDateTime}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = {k: util.deserialize_datetime(v) for k, v in flask.request.get_json().items()} # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {k: util.deserialize_datetime(v) for k, v in {{paramName}}.items()} # noqa: E501 + {{/isBodyParam}} {{/isDateTime}} {{#complexType}} + {{#isBodyParam}} if flask.request.is_json: {{paramName}} = {k: {{baseType}}.from_dict(v) for k, v in flask.request.get_json().items()} # noqa: E501 + {{/isBodyParam}} + {{^isBodyParam}} + if isinstance({{paramName}}, dict): + {{paramName}} = {k: {{baseType}}.from_dict(v) for k, v in {{paramName}}.items()} # noqa: E501 + {{/isBodyParam}} {{/complexType}} {{/items}} {{/isMap}} diff --git a/modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache b/modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache index 586dc3c8679b..f782a35e158b 100644 --- a/modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache +++ b/modules/openapi-generator/src/main/resources/python-flask/controller_test.mustache @@ -28,7 +28,7 @@ class {{#operations}}Test{{classname}}(BaseTestCase): headers = { {{#vendorExtensions.x-preferred-produce}} 'Accept': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-produce}}{{#vendorExtensions.x-preferred-consume}} 'Content-Type': '{{{mediaType}}}',{{/vendorExtensions.x-preferred-consume}}{{#headerParams}} - '{{paramName}}': {{{example}}},{{/headerParams}}{{#authMethods}} + '{{baseName}}': {{{example}}},{{/headerParams}}{{#authMethods}} {{#isOAuth}}'Authorization': 'Bearer special-key',{{/isOAuth}}{{#isApiKey}}'{{name}}': 'special-key',{{/isApiKey}}{{#isBasicBasic}}'Authorization': 'Basic Zm9vOmJhcg==',{{/isBasicBasic}}{{#isBasicBearer}}'Authorization': 'Bearer special-key',{{/isBasicBearer}}{{/authMethods}} } {{#formParams}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java index c4133bf1ccd5..a0b1cc5edf94 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java @@ -3,16 +3,26 @@ import com.google.common.collect.ImmutableMap; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.DefaultGenerator; +import org.openapitools.codegen.config.CodegenConfigurator; import org.openapitools.codegen.languages.AbstractPythonConnexionServerCodegen; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; +import static org.openapitools.codegen.TestUtils.assertFileContains; +import static org.openapitools.codegen.TestUtils.assertFileExists; +import static org.openapitools.codegen.TestUtils.assertFileNotContains; import static org.openapitools.codegen.languages.AbstractPythonConnexionServerCodegen.*; public class AbstractPythonConnexionServerCodegenTest { @@ -142,4 +152,230 @@ private static String platformAgnosticPath(String... nodes) { return StringUtils.join(nodes, File.separatorChar); } + private static Path generateOutputDir(String generatorName, Map additionalProperties) throws IOException { + File output = Files.createTempDirectory("test-" + generatorName).toFile().getCanonicalFile(); + output.deleteOnExit(); + + CodegenConfigurator config = new CodegenConfigurator() + .setGeneratorName(generatorName) + .setInputSpec("src/test/resources/3_0/python/connexion-param-sources.yaml") + .setOutputDir(output.getAbsolutePath()); + for (Map.Entry entry : additionalProperties.entrySet()) { + config.addAdditionalProperty(entry.getKey(), entry.getValue()); + } + + List files = new DefaultGenerator().opts(config.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + return output.toPath(); + } + + @Test(description = "header and cookie parameters are read from request with type conversion and defaults rather than declared as Connexion handler arguments") + public void testHeaderParamsReadFromRequestHeadersInConnexionControllers() throws IOException { + Path aiohttpDir = generateOutputDir("python-aiohttp", Collections.emptyMap()); + Path aiohttpController = aiohttpDir.resolve(Paths.get("openapi_server", "controllers", "default_controller.py")); + Path aiohttpTest = aiohttpDir.resolve(Paths.get("tests", "test_default_controller.py")); + assertFileExists(aiohttpController); + assertFileExists(aiohttpTest); + assertFileContains( + aiohttpController, + "import json", + "async def create_item(request: web.Request, filter_param, body, date_list=None, model_map=None) -> web.Response:", + "x_req_header = request.headers.get('X-Req-Header')", + "x_int_header = request.headers.get('X-Int-Header', 7)", + "x_int_header = int(x_int_header)", + "x_num_header = request.headers.get('X-Num-Header', 1.5)", + "x_num_header = float(x_num_header)", + "x_bool_header = request.headers.get('X-Bool-Header', True)", + "x_bool_header = x_bool_header.lower() == 'true'", + "x_opt_date = request.headers.get('X-Opt-Date')", + "if x_opt_date is not None:", + "x_opt_date = util.deserialize_date(x_opt_date)", + "x_json_header = request.headers.get('X-Json-Header')", + "x_json_header = json.loads(x_json_header)", + "x_json_header = HeaderArg.from_dict(x_json_header)", + "x_tag_list = request.headers.get('X-Tag-List', ['foo', 'bar'])", + "x_tag_list = x_tag_list.split(',')", + "x_flag_list = request.headers.get('X-Flag-List', [True, False])", + "x_flag_list = [x.lower() == 'true' if isinstance(x, str) else bool(x) for x in x_flag_list]", + "x_date_list = request.headers.get('X-Date-List')", + "x_date_list = x_date_list.split(',')", + "if isinstance(x_date_list, list):", + "x_date_list = [util.deserialize_date(s) for s in x_date_list]", + "x_status_list = request.headers.get('X-Status-List')", + "x_status_list = x_status_list.split(',')", + "x_status_list = [StatusEnum.from_dict(d) for d in x_status_list]", + "x_obj_list = request.headers.get('X-Obj-List', [{'tag': 'alpha'}, {'tag': 'beta'}])", + "x_obj_list = [QueryFilter.from_dict(d) for d in x_obj_list]", + "x_nested_list = request.headers.get('X-Nested-List', [['a', 'b'], ['c']])", + "session_token = request.cookies.get('session_token', 'default-cookie')", + "opt_datetime = request.cookies.get('opt_datetime')", + "if opt_datetime is not None:", + "opt_datetime = util.deserialize_datetime(opt_datetime)", + "ids = request.cookies.get('ids', [1, 2])", + "ids = ids.split(',')", + "ids = [int(x) for x in ids]", + "json_cookie = request.cookies.get('json_cookie')", + "json_cookie = json.loads(json_cookie)", + "json_cookie = HeaderArg.from_dict(json_cookie)"); + assertFileNotContains(aiohttpController, "async def create_item(request: web.Request, x_req_header"); + assertFileNotContains(aiohttpController, "session_token=None"); + assertFileNotContains(aiohttpController, "[foo, bar]"); + assertFileNotContains(aiohttpController, "[true, false]"); + assertFileNotContains(aiohttpController, "['', '']"); + assertFileNotContains(aiohttpController, "x_obj_list.split(',')"); + assertFileContains(aiohttpTest, "'X-Req-Header':"); + assertFileNotContains(aiohttpTest, "'x_req_header':"); + + Path blueplanetDir = generateOutputDir("python-blueplanet", Collections.emptyMap()); + Path blueplanetController = blueplanetDir.resolve(Paths.get("app", "openapi_server", "controllers", "default_controller.py")); + Path blueplanetTest = blueplanetDir.resolve(Paths.get("app", "openapi_server", "test", "test_default_controller.py")); + assertFileExists(blueplanetController); + assertFileExists(blueplanetTest); + assertFileContains( + blueplanetController, + "import json", + "def create_item(filter_param, body, date_list=None, model_map=None): # noqa: E501", + "x_req_header = connexion.request.headers.get('X-Req-Header')", + "x_int_header = connexion.request.headers.get('X-Int-Header', 7)", + "x_int_header = int(x_int_header)", + "x_num_header = connexion.request.headers.get('X-Num-Header', 1.5)", + "x_num_header = float(x_num_header)", + "x_bool_header = connexion.request.headers.get('X-Bool-Header', True)", + "x_bool_header = x_bool_header.lower() == 'true'", + "x_opt_date = connexion.request.headers.get('X-Opt-Date')", + "if x_opt_date is not None:", + "x_opt_date = util.deserialize_date(x_opt_date)", + "x_json_header = connexion.request.headers.get('X-Json-Header')", + "x_json_header = json.loads(x_json_header)", + "x_json_header = HeaderArg.from_dict(x_json_header) # noqa: E501", + "x_tag_list = connexion.request.headers.get('X-Tag-List', ['foo', 'bar'])", + "x_tag_list = x_tag_list.split(',')", + "x_flag_list = connexion.request.headers.get('X-Flag-List', [True, False])", + "x_flag_list = [x.lower() == 'true' if isinstance(x, str) else bool(x) for x in x_flag_list]", + "x_status_list = connexion.request.headers.get('X-Status-List')", + "x_status_list = x_status_list.split(',')", + "x_status_list = [StatusEnum.from_dict(d) for d in x_status_list] # noqa: E501", + "x_obj_list = connexion.request.headers.get('X-Obj-List', [{'tag': 'alpha'}, {'tag': 'beta'}])", + "x_obj_list = [QueryFilter.from_dict(d) for d in x_obj_list] # noqa: E501", + "x_nested_list = connexion.request.headers.get('X-Nested-List', [['a', 'b'], ['c']])", + "session_token = connexion.request.cookies.get('session_token', 'default-cookie')", + "opt_datetime = connexion.request.cookies.get('opt_datetime')", + "if opt_datetime is not None:", + "opt_datetime = util.deserialize_datetime(opt_datetime)", + "ids = connexion.request.cookies.get('ids', [1, 2])", + "ids = ids.split(',')", + "ids = [int(x) for x in ids]", + "json_cookie = connexion.request.cookies.get('json_cookie')", + "json_cookie = json.loads(json_cookie)", + "json_cookie = HeaderArg.from_dict(json_cookie) # noqa: E501"); + assertFileNotContains(blueplanetController, "def create_item(x_req_header"); + assertFileNotContains(blueplanetController, "session_token=None"); + assertFileNotContains(blueplanetController, "[foo, bar]"); + assertFileNotContains(blueplanetController, "[true, false]"); + assertFileNotContains(blueplanetController, "['', '']"); + assertFileNotContains(blueplanetController, "x_obj_list.split(',')"); + assertFileContains(blueplanetTest, "('X-Req-Header',"); + assertFileNotContains(blueplanetTest, "('x_req_header',"); + + for (Map props : new Map[]{Collections.emptyMap(), ImmutableMap.of("useConnexion3", "true")}) { + Path flaskDir = generateOutputDir("python-flask", props); + Path flaskController = flaskDir.resolve(Paths.get("openapi_server", "controllers", "default_controller.py")); + Path flaskTest = flaskDir.resolve(Paths.get("openapi_server", "test", "test_default_controller.py")); + assertFileExists(flaskController); + assertFileExists(flaskTest); + assertFileContains( + flaskController, + "import json", + "def create_item(filter_param, body, date_list=None, model_map=None): # noqa: E501", + "x_req_header = flask.request.headers.get('X-Req-Header')", + "x_int_header = flask.request.headers.get('X-Int-Header', 7)", + "x_int_header = int(x_int_header)", + "x_num_header = flask.request.headers.get('X-Num-Header', 1.5)", + "x_num_header = float(x_num_header)", + "x_bool_header = flask.request.headers.get('X-Bool-Header', True)", + "x_bool_header = x_bool_header.lower() == 'true'", + "x_opt_date = flask.request.headers.get('X-Opt-Date')", + "if x_opt_date is not None:", + "x_opt_date = util.deserialize_date(x_opt_date)", + "x_json_header = flask.request.headers.get('X-Json-Header')", + "x_json_header = json.loads(x_json_header)", + "x_json_header = HeaderArg.from_dict(x_json_header) # noqa: E501", + "x_tag_list = flask.request.headers.get('X-Tag-List', ['foo', 'bar'])", + "x_tag_list = x_tag_list.split(',')", + "x_flag_list = flask.request.headers.get('X-Flag-List', [True, False])", + "x_flag_list = [x.lower() == 'true' if isinstance(x, str) else bool(x) for x in x_flag_list]", + "x_status_list = flask.request.headers.get('X-Status-List')", + "x_status_list = x_status_list.split(',')", + "x_status_list = [StatusEnum.from_dict(d) for d in x_status_list] # noqa: E501", + "x_obj_list = flask.request.headers.get('X-Obj-List', [{'tag': 'alpha'}, {'tag': 'beta'}])", + "x_obj_list = [QueryFilter.from_dict(d) for d in x_obj_list] # noqa: E501", + "x_nested_list = flask.request.headers.get('X-Nested-List', [['a', 'b'], ['c']])", + "session_token = flask.request.cookies.get('session_token', 'default-cookie')", + "opt_datetime = flask.request.cookies.get('opt_datetime')", + "if opt_datetime is not None:", + "opt_datetime = util.deserialize_datetime(opt_datetime)", + "ids = flask.request.cookies.get('ids', [1, 2])", + "ids = ids.split(',')", + "ids = [int(x) for x in ids]", + "json_cookie = flask.request.cookies.get('json_cookie')", + "json_cookie = json.loads(json_cookie)", + "json_cookie = HeaderArg.from_dict(json_cookie) # noqa: E501"); + assertFileNotContains(flaskController, "def create_item(x_req_header"); + assertFileNotContains(flaskController, "session_token=None"); + assertFileNotContains(flaskController, "[foo, bar]"); + assertFileNotContains(flaskController, "[true, false]"); + assertFileNotContains(flaskController, "['', '']"); + assertFileNotContains(flaskController, "x_obj_list.split(',')"); + assertFileContains(flaskTest, "'X-Req-Header':"); + assertFileNotContains(flaskTest, "'x_req_header':"); + } + } + + @Test(description = "non-body model, array, and map parameters are deserialized from their argument value rather than overwritten from request.get_json()") + public void testNonBodyModelParamsNotOverwrittenFromRequestBody() throws IOException { + Path aiohttpController = generateOutputDir("python-aiohttp", Collections.emptyMap()) + .resolve(Paths.get("openapi_server", "controllers", "default_controller.py")); + assertFileContains( + aiohttpController, + "if isinstance(filter_param, dict):", + "filter_param = QueryFilter.from_dict(filter_param)", + "body = BodyPayload.from_dict(body)"); + assertFileNotContains(aiohttpController, "= .from_dict("); + + Path blueplanetController = generateOutputDir("python-blueplanet", Collections.emptyMap()) + .resolve(Paths.get("app", "openapi_server", "controllers", "default_controller.py")); + assertFileContains( + blueplanetController, + "if isinstance(filter_param, dict):", + "filter_param = QueryFilter.from_dict(filter_param) # noqa: E501", + "if isinstance(date_list, list):", + "date_list = [util.deserialize_date(s) for s in date_list] # noqa: E501", + "if isinstance(model_map, dict):", + "model_map = {k: QueryFilter.from_dict(v) for k, v in model_map.items()} # noqa: E501", + "body = BodyPayload.from_dict(connexion.request.get_json()) # noqa: E501"); + assertFileNotContains(blueplanetController, "QueryFilter.from_dict(connexion.request.get_json())"); + assertFileNotContains(blueplanetController, "deserialize_date(s) for s in connexion.request.get_json()"); + assertFileNotContains(blueplanetController, "connexion.request.get_json().items()"); + assertFileNotContains(blueplanetController, "= .from_dict("); + + for (Map props : new Map[]{Collections.emptyMap(), ImmutableMap.of("useConnexion3", "true")}) { + Path flaskController = generateOutputDir("python-flask", props) + .resolve(Paths.get("openapi_server", "controllers", "default_controller.py")); + assertFileContains( + flaskController, + "if isinstance(filter_param, dict):", + "filter_param = QueryFilter.from_dict(filter_param) # noqa: E501", + "if isinstance(date_list, list):", + "date_list = [util.deserialize_date(s) for s in date_list] # noqa: E501", + "if isinstance(model_map, dict):", + "model_map = {k: QueryFilter.from_dict(v) for k, v in model_map.items()} # noqa: E501", + "body_payload = body", + "body_payload = BodyPayload.from_dict(flask.request.get_json()) # noqa: E501"); + assertFileNotContains(flaskController, "QueryFilter.from_dict(flask.request.get_json())"); + assertFileNotContains(flaskController, "deserialize_date(s) for s in flask.request.get_json()"); + assertFileNotContains(flaskController, "flask.request.get_json().items()"); + } + } + } diff --git a/modules/openapi-generator/src/test/resources/3_0/python/connexion-param-sources.yaml b/modules/openapi-generator/src/test/resources/3_0/python/connexion-param-sources.yaml new file mode 100644 index 000000000000..5b2fed5337cc --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/python/connexion-param-sources.yaml @@ -0,0 +1,191 @@ +openapi: 3.0.3 +info: + title: Connexion parameter sources test + version: 1.0.0 +servers: + - url: /v1 +paths: + /items: + post: + operationId: create_item + parameters: + - name: X-Req-Header + in: header + required: true + schema: + type: string + - name: X-Int-Header + in: header + required: false + schema: + type: integer + default: 7 + - name: X-Num-Header + in: header + required: false + schema: + type: number + default: 1.5 + - name: X-Bool-Header + in: header + required: false + schema: + type: boolean + default: true + - name: X-Opt-Date + in: header + required: false + schema: + type: string + format: date + - name: X-Json-Header + in: header + required: false + content: + application/json: + schema: + $ref: '#/components/schemas/HeaderArg' + - name: X-Tag-List + in: header + required: false + schema: + type: array + items: + type: string + default: + - foo + - bar + - name: X-Flag-List + in: header + required: false + schema: + type: array + items: + type: boolean + default: + - true + - false + - name: X-Date-List + in: header + required: false + schema: + type: array + items: + type: string + format: date + - name: X-Status-List + in: header + required: false + schema: + type: array + items: + $ref: '#/components/schemas/StatusEnum' + - name: X-Obj-List + in: header + required: false + schema: + type: array + items: + $ref: '#/components/schemas/QueryFilter' + default: + - tag: alpha + - tag: beta + - name: X-Nested-List + in: header + required: false + schema: + type: array + items: + type: array + items: + type: string + default: + - - a + - b + - - c + - name: session_token + in: cookie + required: false + schema: + type: string + default: default-cookie + - name: opt_datetime + in: cookie + required: false + schema: + type: string + format: date-time + - name: ids + in: cookie + required: false + schema: + type: array + items: + type: integer + default: + - 1 + - 2 + - name: json_cookie + in: cookie + required: false + content: + application/json: + schema: + $ref: '#/components/schemas/HeaderArg' + - name: filter_param + in: query + required: true + style: deepObject + explode: true + schema: + $ref: '#/components/schemas/QueryFilter' + - name: date_list + in: query + required: false + schema: + type: array + items: + type: string + format: date + - name: model_map + in: query + required: false + schema: + type: object + additionalProperties: + $ref: '#/components/schemas/QueryFilter' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BodyPayload' + responses: + '200': + description: OK + content: + application/json: + schema: + type: object +components: + schemas: + StatusEnum: + type: string + enum: + - active + - archived + HeaderArg: + type: object + properties: + mode: + type: string + QueryFilter: + type: object + properties: + tag: + type: string + BodyPayload: + type: object + properties: + item_name: + type: string diff --git a/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/controllers/pet_controller.py b/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/controllers/pet_controller.py index ad7557832bab..908f776a5401 100644 --- a/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/controllers/pet_controller.py +++ b/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/controllers/pet_controller.py @@ -19,7 +19,7 @@ async def add_pet(request: web.Request, body) -> web.Response: return web.Response(status=200) -async def delete_pet(request: web.Request, pet_id, api_key=None) -> web.Response: +async def delete_pet(request: web.Request, pet_id) -> web.Response: """Deletes a pet @@ -30,6 +30,7 @@ async def delete_pet(request: web.Request, pet_id, api_key=None) -> web.Response :type api_key: str """ + api_key = request.headers.get('api_key') return web.Response(status=200) diff --git a/samples/server/petstore/python-blueplanet/app/openapi_server/controllers/pet_controller.py b/samples/server/petstore/python-blueplanet/app/openapi_server/controllers/pet_controller.py index 9a6239dc04d5..7ef5d0d62f2f 100644 --- a/samples/server/petstore/python-blueplanet/app/openapi_server/controllers/pet_controller.py +++ b/samples/server/petstore/python-blueplanet/app/openapi_server/controllers/pet_controller.py @@ -20,7 +20,7 @@ def add_pet(body): # noqa: E501 return 'do some magic!' -def delete_pet(pet_id, api_key=None): # noqa: E501 +def delete_pet(pet_id): # noqa: E501 """Deletes a pet # noqa: E501 @@ -32,6 +32,7 @@ def delete_pet(pet_id, api_key=None): # noqa: E501 :rtype: None """ + api_key = connexion.request.headers.get('api_key') return 'do some magic!' diff --git a/samples/server/petstore/python-flask-connexion3/openapi_server/controllers/pet_controller.py b/samples/server/petstore/python-flask-connexion3/openapi_server/controllers/pet_controller.py index 9023d28028d1..62d9ba72c5e7 100644 --- a/samples/server/petstore/python-flask-connexion3/openapi_server/controllers/pet_controller.py +++ b/samples/server/petstore/python-flask-connexion3/openapi_server/controllers/pet_controller.py @@ -24,7 +24,7 @@ def add_pet(body): # noqa: E501 return 'do some magic!' -def delete_pet(pet_id, api_key=None): # noqa: E501 +def delete_pet(pet_id): # noqa: E501 """Deletes a pet # noqa: E501 @@ -36,6 +36,7 @@ def delete_pet(pet_id, api_key=None): # noqa: E501 :rtype: Union[None, Tuple[None, int], Tuple[None, int, Dict[str, str]] """ + api_key = flask.request.headers.get('api_key') return 'do some magic!' diff --git a/samples/server/petstore/python-flask/openapi_server/controllers/pet_controller.py b/samples/server/petstore/python-flask/openapi_server/controllers/pet_controller.py index 9023d28028d1..62d9ba72c5e7 100644 --- a/samples/server/petstore/python-flask/openapi_server/controllers/pet_controller.py +++ b/samples/server/petstore/python-flask/openapi_server/controllers/pet_controller.py @@ -24,7 +24,7 @@ def add_pet(body): # noqa: E501 return 'do some magic!' -def delete_pet(pet_id, api_key=None): # noqa: E501 +def delete_pet(pet_id): # noqa: E501 """Deletes a pet # noqa: E501 @@ -36,6 +36,7 @@ def delete_pet(pet_id, api_key=None): # noqa: E501 :rtype: Union[None, Tuple[None, int], Tuple[None, int, Dict[str, str]] """ + api_key = flask.request.headers.get('api_key') return 'do some magic!'