diff --git a/docs/generators/python-aiohttp.md b/docs/generators/python-aiohttp.md
index ded84c55242..7fbe2222c6a 100644
--- a/docs/generators/python-aiohttp.md
+++ b/docs/generators/python-aiohttp.md
@@ -42,13 +42,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
Dict
List
bool
-byte
-bytearray
+bytes
date
datetime
+dict
file
float
int
+list
object
str
@@ -56,9 +57,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## RESERVED WORDS
+- all_params
- and
- as
- assert
+- async
+- auth_settings
+- await
+- body_params
- break
- class
- continue
@@ -71,21 +77,27 @@ These options may be applied as additional-properties (cli) or configOptions (pl
- false
- finally
- for
+- form_params
- from
- global
+- header_params
- if
- import
- in
- is
- lambda
+- local_var_files
- none
- nonlocal
- not
- or
- pass
+- path_params
- print
- property
+- query_params
- raise
+- resource_path
- return
- self
- true
diff --git a/docs/generators/python-blueplanet.md b/docs/generators/python-blueplanet.md
index eb4fdab9aa1..98ee0ad8184 100644
--- a/docs/generators/python-blueplanet.md
+++ b/docs/generators/python-blueplanet.md
@@ -42,13 +42,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
- Dict
- List
- bool
-- byte
-- bytearray
+- bytes
- date
- datetime
+- dict
- file
- float
- int
+- list
- object
- str
@@ -56,9 +57,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## RESERVED WORDS
+- all_params
- and
- as
- assert
+- async
+- auth_settings
+- await
+- body_params
- break
- class
- continue
@@ -71,21 +77,27 @@ These options may be applied as additional-properties (cli) or configOptions (pl
- false
- finally
- for
+- form_params
- from
- global
+- header_params
- if
- import
- in
- is
- lambda
+- local_var_files
- none
- nonlocal
- not
- or
- pass
+- path_params
- print
- property
+- query_params
- raise
+- resource_path
- return
- self
- true
diff --git a/docs/generators/python-flask.md b/docs/generators/python-flask.md
index a0b17be6482..372272b45ce 100644
--- a/docs/generators/python-flask.md
+++ b/docs/generators/python-flask.md
@@ -42,13 +42,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
- Dict
- List
- bool
-- byte
-- bytearray
+- bytes
- date
- datetime
+- dict
- file
- float
- int
+- list
- object
- str
@@ -56,9 +57,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## RESERVED WORDS
+- all_params
- and
- as
- assert
+- async
+- auth_settings
+- await
+- body_params
- break
- class
- continue
@@ -71,21 +77,27 @@ These options may be applied as additional-properties (cli) or configOptions (pl
- false
- finally
- for
+- form_params
- from
- global
+- header_params
- if
- import
- in
- is
- lambda
+- local_var_files
- none
- nonlocal
- not
- or
- pass
+- path_params
- print
- property
+- query_params
- raise
+- resource_path
- return
- self
- true
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java
new file mode 100644
index 00000000000..d3482e1724e
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java
@@ -0,0 +1,702 @@
+/*
+ * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openapitools.codegen.languages;
+
+import com.github.curiousoddman.rgxgen.RgxGen;
+import io.swagger.v3.oas.models.examples.Example;
+import io.swagger.v3.oas.models.media.ArraySchema;
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.parameters.Parameter;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.openapitools.codegen.*;
+import org.openapitools.codegen.utils.ModelUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.openapitools.codegen.utils.StringUtils.camelize;
+import static org.openapitools.codegen.utils.StringUtils.underscore;
+
+abstract public class AbstractPythonCodegen extends DefaultCodegen implements CodegenConfig {
+ private final Logger LOGGER = LoggerFactory.getLogger(AbstractPythonCodegen.class);
+
+ protected String packageName = "openapi_client";
+ protected String packageVersion = "1.0.0";
+ protected String projectName; // for setup.py, e.g. petstore-api
+
+ public AbstractPythonCodegen() {
+ super();
+
+ // from https://docs.python.org/3/reference/lexical_analysis.html#keywords
+ setReservedWordsLowerCase(
+ Arrays.asList(
+ // local variable name used in API methods (endpoints)
+ "all_params", "resource_path", "path_params", "query_params",
+ "header_params", "form_params", "local_var_files", "body_params", "auth_settings",
+ // @property
+ "property",
+ // python reserved words
+ "and", "del", "from", "not", "while", "as", "elif", "global", "or", "with",
+ "assert", "else", "if", "pass", "yield", "break", "except", "import",
+ "print", "class", "exec", "in", "raise", "continue", "finally", "is",
+ "return", "def", "for", "lambda", "try", "self", "nonlocal", "None", "True",
+ "False", "async", "await"));
+
+ languageSpecificPrimitives.clear();
+ languageSpecificPrimitives.add("int");
+ languageSpecificPrimitives.add("float");
+ languageSpecificPrimitives.add("list");
+ languageSpecificPrimitives.add("dict");
+ languageSpecificPrimitives.add("bool");
+ languageSpecificPrimitives.add("str");
+ languageSpecificPrimitives.add("datetime");
+ languageSpecificPrimitives.add("date");
+ languageSpecificPrimitives.add("object");
+ // TODO file and binary is mapped as `file`
+ languageSpecificPrimitives.add("file");
+ languageSpecificPrimitives.add("bytes");
+
+ typeMapping.clear();
+ typeMapping.put("integer", "int");
+ typeMapping.put("float", "float");
+ typeMapping.put("number", "float");
+ typeMapping.put("long", "int");
+ typeMapping.put("double", "float");
+ typeMapping.put("array", "list");
+ typeMapping.put("set", "list");
+ typeMapping.put("map", "dict");
+ typeMapping.put("boolean", "bool");
+ typeMapping.put("string", "str");
+ typeMapping.put("date", "date");
+ typeMapping.put("DateTime", "datetime");
+ typeMapping.put("object", "object");
+ typeMapping.put("AnyType", "object");
+ typeMapping.put("file", "file");
+ // TODO binary should be mapped to byte array
+ // mapped to String as a workaround
+ typeMapping.put("binary", "str");
+ typeMapping.put("ByteArray", "str");
+ // map uuid to string for the time being
+ typeMapping.put("UUID", "str");
+ typeMapping.put("URI", "str");
+ typeMapping.put("null", "none_type");
+ }
+
+ @Override
+ public void processOpts() {
+ super.processOpts();
+
+ if (StringUtils.isEmpty(System.getenv("PYTHON_POST_PROCESS_FILE"))) {
+ LOGGER.info("Environment variable PYTHON_POST_PROCESS_FILE not defined so the Python code may not be properly formatted. To define it, try 'export PYTHON_POST_PROCESS_FILE=\"/usr/local/bin/yapf -i\"' (Linux/Mac)");
+ LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
+ }
+ }
+
+ @Override
+ public String escapeReservedWord(String name) {
+ if (this.reservedWordsMappings().containsKey(name)) {
+ return this.reservedWordsMappings().get(name);
+ }
+ return "_" + name;
+ }
+
+ @Override
+ public String getTypeDeclaration(Schema p) {
+ if (ModelUtils.isArraySchema(p)) {
+ ArraySchema ap = (ArraySchema) p;
+ Schema inner = ap.getItems();
+ return getSchemaType(p) + "[" + getTypeDeclaration(inner) + "]";
+ } else if (ModelUtils.isMapSchema(p)) {
+ Schema inner = getAdditionalProperties(p);
+
+ return getSchemaType(p) + "(str, " + getTypeDeclaration(inner) + ")";
+ }
+ return super.getTypeDeclaration(p);
+ }
+
+ /**
+ * Return the default value of the property
+ *
+ * @param p OpenAPI property object
+ * @return string presentation of the default value of the property
+ */
+ @Override
+ public String toDefaultValue(Schema p) {
+ if (ModelUtils.isBooleanSchema(p)) {
+ if (p.getDefault() != null) {
+ if (Boolean.valueOf(p.getDefault().toString()) == false)
+ return "False";
+ else
+ return "True";
+ }
+ } else if (ModelUtils.isDateSchema(p)) {
+ // TODO
+ } else if (ModelUtils.isDateTimeSchema(p)) {
+ // TODO
+ } else if (ModelUtils.isNumberSchema(p)) {
+ if (p.getDefault() != null) {
+ return p.getDefault().toString();
+ }
+ } else if (ModelUtils.isIntegerSchema(p)) {
+ if (p.getDefault() != null) {
+ return p.getDefault().toString();
+ }
+ } else if (ModelUtils.isStringSchema(p)) {
+ if (p.getDefault() != null) {
+ if (Pattern.compile("\r\n|\r|\n").matcher((String) p.getDefault()).find())
+ return "'''" + p.getDefault() + "'''";
+ else
+ return "'" + ((String) p.getDefault()).replaceAll("'", "\'") + "'";
+ }
+ } else if (ModelUtils.isArraySchema(p)) {
+ if (p.getDefault() != null) {
+ return p.getDefault().toString();
+ }
+ }
+
+ return null;
+ }
+
+
+ @Override
+ public String toVarName(String name) {
+ // sanitize name
+ name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
+
+ // remove dollar sign
+ name = name.replaceAll("$", "");
+
+ // if it's all uppper case, convert to lower case
+ if (name.matches("^[A-Z_]*$")) {
+ name = name.toLowerCase(Locale.ROOT);
+ }
+
+ // underscore the variable name
+ // petId => pet_id
+ name = underscore(name);
+
+ // remove leading underscore
+ name = name.replaceAll("^_*", "");
+
+ // for reserved word or word starting with number, append _
+ if (isReservedWord(name) || name.matches("^\\d.*")) {
+ name = escapeReservedWord(name);
+ }
+
+ return name;
+ }
+
+ @Override
+ public String toRegularExpression(String pattern) {
+ return addRegularExpressionDelimiter(pattern);
+ }
+
+ @Override
+ public String toParamName(String name) {
+ // to avoid conflicts with 'callback' parameter for async call
+ if ("callback".equals(name)) {
+ return "param_callback";
+ }
+
+ // should be the same as variable name
+ return toVarName(name);
+ }
+
+ @Override
+ public String toOperationId(String operationId) {
+ // throw exception if method name is empty (should not occur as an auto-generated method name will be used)
+ if (StringUtils.isEmpty(operationId)) {
+ throw new RuntimeException("Empty method name (operationId) not allowed");
+ }
+
+ // method name cannot use reserved keyword, e.g. return
+ if (isReservedWord(operationId)) {
+ LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
+ operationId = "call_" + operationId;
+ }
+
+ // operationId starts with a number
+ if (operationId.matches("^\\d.*")) {
+ LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
+ operationId = "call_" + operationId;
+ }
+
+ return underscore(sanitizeName(operationId));
+ }
+
+ @Override
+ public String escapeQuotationMark(String input) {
+ // remove ' to avoid code injection
+ return input.replace("'", "");
+ }
+
+ @Override
+ public String escapeUnsafeCharacters(String input) {
+ // remove multiline comment
+ return input.replace("'''", "'_'_'");
+ }
+
+ @Override
+ public void postProcessFile(File file, String fileType) {
+ if (file == null) {
+ return;
+ }
+ String pythonPostProcessFile = System.getenv("PYTHON_POST_PROCESS_FILE");
+ if (StringUtils.isEmpty(pythonPostProcessFile)) {
+ return; // skip if PYTHON_POST_PROCESS_FILE env variable is not defined
+ }
+
+ // only process files with py extension
+ if ("py".equals(FilenameUtils.getExtension(file.toString()))) {
+ String command = pythonPostProcessFile + " " + file.toString();
+ try {
+ Process p = Runtime.getRuntime().exec(command);
+ int exitValue = p.waitFor();
+ if (exitValue != 0) {
+ LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
+ } else {
+ LOGGER.info("Successfully executed: " + command);
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public String toExampleValue(Schema schema) {
+ return toExampleValueRecursive(schema, new ArrayList(), 5);
+ }
+
+ private String toExampleValueRecursive(Schema schema, List included_schemas, int indentation) {
+ String indentation_string = "";
+ for (int i = 0; i < indentation; i++) indentation_string += " ";
+ String example = null;
+ if (schema.getExample() != null) {
+ example = schema.getExample().toString();
+ }
+
+ if (ModelUtils.isNullType(schema) && null != example) {
+ // The 'null' type is allowed in OAS 3.1 and above. It is not supported by OAS 3.0.x,
+ // though this tooling supports it.
+ return "None";
+ }
+ // correct "true"s into "True"s, since super.toExampleValue uses "toString()" on Java booleans
+ if (ModelUtils.isBooleanSchema(schema) && null != example) {
+ if ("false".equalsIgnoreCase(example)) example = "False";
+ else example = "True";
+ }
+
+ // correct "'"s into "'"s after toString()
+ if (ModelUtils.isStringSchema(schema) && schema.getDefault() != null && !ModelUtils.isDateSchema(schema) && !ModelUtils.isDateTimeSchema(schema)) {
+ example = (String) schema.getDefault();
+ }
+
+ if (StringUtils.isNotBlank(example) && !"null".equals(example)) {
+ if (ModelUtils.isStringSchema(schema)) {
+ example = "'" + example + "'";
+ }
+ return example;
+ }
+
+ if (schema.getEnum() != null && !schema.getEnum().isEmpty()) {
+ // Enum case:
+ example = schema.getEnum().get(0).toString();
+ if (ModelUtils.isStringSchema(schema)) {
+ example = "'" + escapeText(example) + "'";
+ }
+ if (null == example)
+ LOGGER.warn("Empty enum. Cannot built an example!");
+
+ return example;
+ } else if (null != schema.get$ref()) {
+ // $ref case:
+ Map allDefinitions = ModelUtils.getSchemas(this.openAPI);
+ String ref = ModelUtils.getSimpleRef(schema.get$ref());
+ if (allDefinitions != null) {
+ Schema refSchema = allDefinitions.get(ref);
+ if (null == refSchema) {
+ return "None";
+ } else {
+ String refTitle = refSchema.getTitle();
+ if (StringUtils.isBlank(refTitle) || "null".equals(refTitle)) {
+ refSchema.setTitle(ref);
+ }
+ if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
+ included_schemas.add(schema.getTitle());
+ }
+ return toExampleValueRecursive(refSchema, included_schemas, indentation);
+ }
+ } else {
+ LOGGER.warn("allDefinitions not defined in toExampleValue!\n");
+ }
+ }
+ if (ModelUtils.isDateSchema(schema)) {
+ example = "datetime.datetime.strptime('1975-12-30', '%Y-%m-%d').date()";
+ return example;
+ } else if (ModelUtils.isDateTimeSchema(schema)) {
+ example = "datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f')";
+ return example;
+ } else if (ModelUtils.isBinarySchema(schema)) {
+ example = "bytes(b'blah')";
+ return example;
+ } else if (ModelUtils.isByteArraySchema(schema)) {
+ example = "YQ==";
+ } else if (ModelUtils.isStringSchema(schema)) {
+ // a BigDecimal:
+ if ("Number".equalsIgnoreCase(schema.getFormat())) {
+ return "1";
+ }
+ if (StringUtils.isNotBlank(schema.getPattern())) {
+ String pattern = schema.getPattern();
+ RgxGen rgxGen = new RgxGen(patternCorrection(pattern));
+ // this seed makes it so if we have [a-z] we pick a
+ Random random = new Random(18);
+ String sample = rgxGen.generate(random);
+ // omit leading / and trailing /, omit trailing /i
+ Pattern valueExtractor = Pattern.compile("^/\\^?(.+?)\\$?/.?$");
+ Matcher m = valueExtractor.matcher(sample);
+ if (m.find()) {
+ example = m.group(m.groupCount());
+ } else {
+ example = sample;
+ }
+ }
+ if (example == null) {
+ example = "";
+ }
+ int len = 0;
+ if (null != schema.getMinLength()) {
+ len = schema.getMinLength().intValue();
+ if (len < 1) {
+ example = "";
+ } else {
+ for (int i = 0; i < len; i++) example += i;
+ }
+ }
+ } else if (ModelUtils.isIntegerSchema(schema)) {
+ if (schema.getMinimum() != null)
+ example = schema.getMinimum().toString();
+ else
+ example = "56";
+ } else if (ModelUtils.isNumberSchema(schema)) {
+ if (schema.getMinimum() != null)
+ example = schema.getMinimum().toString();
+ else
+ example = "1.337";
+ } else if (ModelUtils.isBooleanSchema(schema)) {
+ example = "True";
+ } else if (ModelUtils.isArraySchema(schema)) {
+ if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
+ included_schemas.add(schema.getTitle());
+ }
+ ArraySchema arrayschema = (ArraySchema) schema;
+ example = "[\n" + indentation_string + toExampleValueRecursive(arrayschema.getItems(), included_schemas, indentation + 1) + "\n" + indentation_string + "]";
+ } else if (ModelUtils.isMapSchema(schema)) {
+ if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
+ included_schemas.add(schema.getTitle());
+ }
+ Object additionalObject = schema.getAdditionalProperties();
+ if (additionalObject instanceof Schema) {
+ Schema additional = (Schema) additionalObject;
+ String the_key = "'key'";
+ if (additional.getEnum() != null && !additional.getEnum().isEmpty()) {
+ the_key = additional.getEnum().get(0).toString();
+ if (ModelUtils.isStringSchema(additional)) {
+ the_key = "'" + escapeText(the_key) + "'";
+ }
+ }
+ example = "{\n" + indentation_string + the_key + " : " + toExampleValueRecursive(additional, included_schemas, indentation + 1) + "\n" + indentation_string + "}";
+ } else {
+ example = "{ }";
+ }
+ } else if (ModelUtils.isObjectSchema(schema)) {
+ if (StringUtils.isBlank(schema.getTitle())) {
+ example = "None";
+ return example;
+ }
+
+ // I remove any property that is a discriminator, since it is not well supported by the python generator
+ String toExclude = null;
+ if (schema.getDiscriminator() != null) {
+ toExclude = schema.getDiscriminator().getPropertyName();
+ }
+
+ example = packageName + ".models." + underscore(schema.getTitle()) + "." + schema.getTitle() + "(";
+
+ // if required only:
+ // List reqs = schema.getRequired();
+
+ // if required and optionals
+ List reqs = new ArrayList<>();
+ if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
+ for (Object toAdd : schema.getProperties().keySet()) {
+ reqs.add((String) toAdd);
+ }
+
+ Map properties = schema.getProperties();
+ Set propkeys = null;
+ if (properties != null) propkeys = properties.keySet();
+ if (toExclude != null && reqs.contains(toExclude)) {
+ reqs.remove(toExclude);
+ }
+ for (String toRemove : included_schemas) {
+ if (reqs.contains(toRemove)) {
+ reqs.remove(toRemove);
+ }
+ }
+ if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
+ included_schemas.add(schema.getTitle());
+ }
+ if (null != schema.getRequired()) for (Object toAdd : schema.getRequired()) {
+ reqs.add((String) toAdd);
+ }
+ if (null != propkeys) for (String propname : propkeys) {
+ Schema schema2 = properties.get(propname);
+ if (reqs.contains(propname)) {
+ String refTitle = schema2.getTitle();
+ if (StringUtils.isBlank(refTitle) || "null".equals(refTitle)) {
+ schema2.setTitle(propname);
+ }
+ example += "\n" + indentation_string + underscore(propname) + " = " +
+ toExampleValueRecursive(schema2, included_schemas, indentation + 1) + ", ";
+ }
+ }
+ }
+ example += ")";
+ } else {
+ LOGGER.warn("Type " + schema.getType() + " not handled properly in toExampleValue");
+ }
+
+ if (ModelUtils.isStringSchema(schema)) {
+ example = "'" + escapeText(example) + "'";
+ }
+
+ return example;
+ }
+
+ @Override
+ public void setParameterExampleValue(CodegenParameter p) {
+ String example;
+
+ if (p.defaultValue == null) {
+ example = p.example;
+ } else {
+ p.example = p.defaultValue;
+ return;
+ }
+
+ String type = p.baseType;
+ if (type == null) {
+ type = p.dataType;
+ }
+
+ if ("String".equalsIgnoreCase(type) || "str".equalsIgnoreCase(type)) {
+ if (example == null) {
+ example = p.paramName + "_example";
+ }
+ example = "'" + escapeText(example) + "'";
+ } else if ("Integer".equals(type) || "int".equals(type)) {
+ if (example == null) {
+ example = "56";
+ }
+ } else if ("Float".equalsIgnoreCase(type) || "Double".equalsIgnoreCase(type)) {
+ if (example == null) {
+ example = "3.4";
+ }
+ } else if ("BOOLEAN".equalsIgnoreCase(type) || "bool".equalsIgnoreCase(type)) {
+ if (example == null) {
+ example = "True";
+ }
+ } else if ("file".equalsIgnoreCase(type)) {
+ if (example == null) {
+ example = "/path/to/file";
+ }
+ example = "'" + escapeText(example) + "'";
+ } else if ("Date".equalsIgnoreCase(type)) {
+ if (example == null) {
+ example = "2013-10-20";
+ }
+ example = "'" + escapeText(example) + "'";
+ } else if ("DateTime".equalsIgnoreCase(type)) {
+ if (example == null) {
+ example = "2013-10-20T19:20:30+01:00";
+ }
+ example = "'" + escapeText(example) + "'";
+ } else if (!languageSpecificPrimitives.contains(type)) {
+ // type is a model class, e.g. User
+ example = this.packageName + "." + type + "()";
+ } else {
+ LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
+ }
+
+ if (example == null) {
+ example = "None";
+ } else if (Boolean.TRUE.equals(p.isArray)) {
+ example = "[" + example + "]";
+ } else if (Boolean.TRUE.equals(p.isMap)) {
+ example = "{'key': " + example + "}";
+ }
+
+ p.example = example;
+ }
+
+ @Override
+ public void setParameterExampleValue(CodegenParameter codegenParameter, Parameter parameter) {
+ Schema schema = parameter.getSchema();
+
+ if (parameter.getExample() != null) {
+ codegenParameter.example = parameter.getExample().toString();
+ } else if (parameter.getExamples() != null && !parameter.getExamples().isEmpty()) {
+ Example example = parameter.getExamples().values().iterator().next();
+ if (example.getValue() != null) {
+ codegenParameter.example = example.getValue().toString();
+ }
+ } else if (schema != null && schema.getExample() != null) {
+ codegenParameter.example = schema.getExample().toString();
+ }
+
+ setParameterExampleValue(codegenParameter);
+ }
+
+ @Override
+ public String sanitizeTag(String tag) {
+ return sanitizeName(tag);
+ }
+
+ public String patternCorrection(String pattern) {
+ // Java does not recognize starting and ending forward slashes and mode modifiers
+ // It considers them as characters with no special meaning and tries to find them in the match string
+ boolean checkEnding = pattern.endsWith("/i") || pattern.endsWith("/g") || pattern.endsWith("/m");
+ if (checkEnding) pattern = pattern.substring(0, pattern.length() - 2);
+ if (pattern.endsWith("/")) pattern = pattern.substring(0, pattern.length() - 1);
+ if (pattern.startsWith("/")) pattern = pattern.substring(1);
+ return pattern;
+ }
+
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public void setProjectName(String projectName) {
+ this.projectName = projectName;
+ }
+
+ public void setPackageVersion(String packageVersion) {
+ this.packageVersion = packageVersion;
+ }
+
+ @Override
+ public String getSchemaType(Schema p) {
+ String openAPIType = super.getSchemaType(p);
+ String type = null;
+ if (typeMapping.containsKey(openAPIType)) {
+ type = typeMapping.get(openAPIType);
+ if (languageSpecificPrimitives.contains(type)) {
+ return type;
+ }
+ } else {
+ type = toModelName(openAPIType);
+ }
+ return type;
+ }
+
+
+ @Override
+ public String toModelName(String name) {
+ name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
+ // remove dollar sign
+ name = name.replaceAll("$", "");
+
+ // model name cannot use reserved keyword, e.g. return
+ if (isReservedWord(name)) {
+ LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name));
+ name = "model_" + name; // e.g. return => ModelReturn (after camelize)
+ }
+
+ // model name starts with number
+ if (name.matches("^\\d.*")) {
+ LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name));
+ name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
+ }
+
+ if (!StringUtils.isEmpty(modelNamePrefix)) {
+ name = modelNamePrefix + "_" + name;
+ }
+
+ if (!StringUtils.isEmpty(modelNameSuffix)) {
+ name = name + "_" + modelNameSuffix;
+ }
+
+ // camelize the model name
+ // phone_number => PhoneNumber
+ return camelize(name);
+ }
+
+ @Override
+ public String toModelFilename(String name) {
+ // underscore the model file name
+ // PhoneNumber => phone_number
+ return underscore(dropDots(toModelName(name)));
+ }
+
+ @Override
+ public String toModelTestFilename(String name) {
+ return "test_" + toModelFilename(name);
+ }
+
+ @Override
+ public String toApiFilename(String name) {
+ // replace - with _ e.g. created-at => created_at
+ name = name.replaceAll("-", "_");
+
+ // e.g. PhoneNumberApi.py => phone_number_api.py
+ return underscore(name + "_" + apiNameSuffix);
+ }
+
+ @Override
+ public String toApiTestFilename(String name) {
+ return "test_" + toApiFilename(name);
+ }
+
+ @Override
+ public String toApiName(String name) {
+ return super.toApiName(name);
+ }
+
+ @Override
+ public String toApiVarName(String name) {
+ if (name.length() == 0) {
+ return "default_api";
+ }
+ return underscore(name + "_" + apiNameSuffix);
+ }
+
+ protected static String dropDots(String str) {
+ return str.replaceAll("\\.", "_");
+ }
+}
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 653c34e37b3..d6972edcdeb 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
@@ -43,7 +43,7 @@ import java.util.*;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;
-public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodegen implements CodegenConfig {
+public abstract class AbstractPythonConnexionServerCodegen extends AbstractPythonCodegen implements CodegenConfig {
private final Logger LOGGER = LoggerFactory.getLogger(AbstractPythonConnexionServerCodegen.class);
public static final String CONTROLLER_PACKAGE = "controllerPackage";
@@ -56,8 +56,6 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
static final String MEDIA_TYPE = "mediaType";
protected int serverPort = 8080;
- protected String packageName;
- protected String packageVersion;
protected String controllerPackage;
protected String defaultController;
protected Map regexModifiers;
@@ -75,49 +73,11 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
modelPackage = "models";
testPackage = "test";
- languageSpecificPrimitives.clear();
- languageSpecificPrimitives.add("int");
- languageSpecificPrimitives.add("float");
+ // TODO may remove these later to default to the setting in abstract python base class instead
languageSpecificPrimitives.add("List");
languageSpecificPrimitives.add("Dict");
- languageSpecificPrimitives.add("bool");
- languageSpecificPrimitives.add("str");
- languageSpecificPrimitives.add("datetime");
- languageSpecificPrimitives.add("date");
- languageSpecificPrimitives.add("file");
- languageSpecificPrimitives.add("object");
- languageSpecificPrimitives.add("byte");
- languageSpecificPrimitives.add("bytearray");
-
- typeMapping.clear();
- typeMapping.put("integer", "int");
- typeMapping.put("float", "float");
- typeMapping.put("number", "float");
- typeMapping.put("long", "int");
- typeMapping.put("double", "float");
typeMapping.put("array", "List");
typeMapping.put("map", "Dict");
- typeMapping.put("boolean", "bool");
- typeMapping.put("string", "str");
- typeMapping.put("date", "date");
- typeMapping.put("DateTime", "datetime");
- typeMapping.put("object", "object");
- typeMapping.put("file", "file");
- typeMapping.put("UUID", "str");
- typeMapping.put("URI", "str");
- typeMapping.put("byte", "bytearray");
- typeMapping.put("ByteArray", "bytearray");
-
- // from https://docs.python.org/3/reference/lexical_analysis.html#keywords
- setReservedWordsLowerCase(
- Arrays.asList(
- // @property
- "property",
- // python reserved words
- "and", "del", "from", "not", "while", "as", "elif", "global", "or", "with",
- "assert", "else", "if", "pass", "yield", "break", "except", "import",
- "print", "class", "exec", "in", "raise", "continue", "finally", "is",
- "return", "def", "for", "lambda", "try", "self", "None", "True", "False", "nonlocal"));
// set the output folder here
outputFolder = "generated-code/connexion";
@@ -182,11 +142,6 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
public void processOpts() {
super.processOpts();
- if (StringUtils.isEmpty(System.getenv("PYTHON_POST_PROCESS_FILE"))) {
- LOGGER.info("Environment variable PYTHON_POST_PROCESS_FILE not defined so the Python code may not be properly formatted. To define it, try 'export PYTHON_POST_PROCESS_FILE=\"/usr/local/bin/yapf -i\"' (Linux/Mac)");
- LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
- }
-
//apiTemplateFiles.clear();
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
@@ -266,6 +221,7 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
}
}
+
public String pythonSrcOutputFolder() {
return outputFolder + File.separator + pythonSrcRoot;
}
@@ -274,10 +230,6 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
return pkg.replace(".", File.separator);
}
- private static String dropDots(String str) {
- return str.replaceAll("\\.", "_");
- }
-
@Override
public String apiPackage() {
return controllerPackage;
@@ -324,20 +276,6 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
return "test_" + toApiFilename(name);
}
- /**
- * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
- * those terms here. This logic is only called if a variable matches the reserved words
- *
- * @return the escaped term
- */
- @Override
- public String escapeReservedWord(String name) {
- if (this.reservedWordsMappings().containsKey(name)) {
- return this.reservedWordsMappings().get(name);
- }
- return "_" + name; // add an underscore to the name
- }
-
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
@@ -367,21 +305,6 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
return super.getTypeDeclaration(p);
}
- @Override
- public String getSchemaType(Schema p) {
- String schemaType = super.getSchemaType(p);
- String type = null;
- if (typeMapping.containsKey(schemaType)) {
- type = typeMapping.get(schemaType);
- if (languageSpecificPrimitives.contains(type)) {
- return type;
- }
- } else {
- type = toModelName(schemaType);
- }
- return type;
- }
-
@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
// need vendor extensions for x-openapi-router-controller
@@ -614,251 +537,11 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
return super.postProcessSupportingFileData(objs);
}
- @Override
- public String toVarName(String name) {
- // sanitize name
- name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
-
- // remove dollar sign
- name = name.replaceAll("$", "");
-
- // if it's all uppper case, convert to lower case
- if (name.matches("^[A-Z_]*$")) {
- name = name.toLowerCase(Locale.ROOT);
- }
-
- // underscore the variable name
- // petId => pet_id
- name = underscore(name);
-
- // remove leading underscore
- name = name.replaceAll("^_*", "");
-
- // for reserved word or word starting with number, append _
- if (isReservedWord(name) || name.matches("^\\d.*")) {
- name = escapeReservedWord(name);
- }
-
- return name;
- }
-
- @Override
- public String toParamName(String name) {
- // to avoid conflicts with 'callback' parameter for async call
- if ("callback".equals(name)) {
- return "param_callback";
- }
-
- // should be the same as variable name
- return toVarName(name);
- }
-
- @Override
- public String toModelFilename(String name) {
- // underscore the model file name
- // PhoneNumber => phone_number
- return underscore(dropDots(toModelName(name)));
- }
-
- @Override
- public String toModelName(String name) {
- name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
- // remove dollar sign
- name = name.replaceAll("$", "");
-
- // model name cannot use reserved keyword, e.g. return
- if (isReservedWord(name)) {
- LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name));
- name = "model_" + name; // e.g. return => ModelReturn (after camelize)
- }
-
- // model name starts with number
- if (name.matches("^\\d.*")) {
- LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name));
- name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
- }
-
- if (!StringUtils.isEmpty(modelNamePrefix)) {
- name = modelNamePrefix + "_" + name;
- }
-
- if (!StringUtils.isEmpty(modelNameSuffix)) {
- name = name + "_" + modelNameSuffix;
- }
-
- // camelize the model name
- // phone_number => PhoneNumber
- return camelize(name);
- }
-
- @Override
- public String toOperationId(String operationId) {
- // throw exception if method name is empty (should not occur as an auto-generated method name will be used)
- if (StringUtils.isEmpty(operationId)) {
- throw new RuntimeException("Empty method name (operationId) not allowed");
- }
-
- // method name cannot use reserved keyword, e.g. return
- if (isReservedWord(operationId)) {
- LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
- operationId = "call_" + operationId;
- }
-
- return underscore(sanitizeName(operationId));
- }
-
- /**
- * Return the default value of the property
- *
- * @param p OpenAPI property object
- * @return string presentation of the default value of the property
- */
- @Override
- public String toDefaultValue(Schema p) {
- if (ModelUtils.isBooleanSchema(p)) {
- if (p.getDefault() != null) {
- if (p.getDefault().toString().equalsIgnoreCase("false"))
- return "False";
- else
- return "True";
- }
- } else if (ModelUtils.isDateSchema(p)) {
- // TODO
- } else if (ModelUtils.isDateTimeSchema(p)) {
- // TODO
- } else if (ModelUtils.isNumberSchema(p)) {
- if (p.getDefault() != null) {
- return p.getDefault().toString();
- }
- } else if (ModelUtils.isIntegerSchema(p)) {
- if (p.getDefault() != null) {
- return p.getDefault().toString();
- }
- } else if (ModelUtils.isStringSchema(p)) {
- if (p.getDefault() != null) {
- return "'" + (String) p.getDefault() + "'";
- }
- }
-
- return null;
- }
-
- @Override
- public void setParameterExampleValue(CodegenParameter p) {
- String example;
-
- if (p.defaultValue == null) {
- example = p.example;
- } else {
- p.example = p.defaultValue;
- return;
- }
-
- String type = p.baseType;
- if (type == null) {
- type = p.dataType;
- }
-
- if ("String".equalsIgnoreCase(type) || "str".equalsIgnoreCase(type)) {
- if (example == null) {
- example = p.paramName + "_example";
- }
- example = "'" + escapeText(example) + "'";
- } else if ("Integer".equals(type) || "int".equals(type)) {
- if (p.minimum != null) {
- example = "" + (Integer.valueOf(p.minimum) + 1);
- }
- if (p.maximum != null) {
- example = "" + p.maximum;
- } else if (example == null) {
- example = "56";
- }
-
- } else if ("Long".equalsIgnoreCase(type)) {
- if (p.minimum != null) {
- example = "" + (Long.valueOf(p.minimum) + 1);
- }
- if (p.maximum != null) {
- example = "" + p.maximum;
- } else if (example == null) {
- example = "789";
- }
- } else if ("Float".equalsIgnoreCase(type) || "Double".equalsIgnoreCase(type)) {
- if (p.minimum != null) {
- example = "" + p.minimum;
- } else if (p.maximum != null) {
- example = "" + p.maximum;
- } else if (example == null) {
- example = "3.4";
- }
- } else if ("BOOLEAN".equalsIgnoreCase(type) || "bool".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "True";
- }
- } else if ("file".equalsIgnoreCase(type)) {
- example = "(BytesIO(b'some file data'), 'file.txt')";
- } else if ("Date".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "2013-10-20";
- }
- example = "'" + escapeText(example) + "'";
- } else if ("DateTime".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "2013-10-20T19:20:30+01:00";
- }
- example = "'" + escapeText(example) + "'";
- } else if (!languageSpecificPrimitives.contains(type)) {
- // type is a model class, e.g. User
- example = "{}";
- } else {
- LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
- }
-
- if (p.items != null && p.items.defaultValue != null) {
- example = p.items.defaultValue;
- }
- if (example == null) {
- if (Boolean.TRUE.equals(p.isArray)) {
- example = "[]";
- } else {
- example = "None";
- }
- } else if (Boolean.TRUE.equals(p.isArray)) {
- if (Boolean.TRUE.equals(p.isBodyParam)) {
- example = "[" + example + "]";
- }
- } else if (Boolean.TRUE.equals(p.isMap)) {
- example = "{'key': " + example + "}";
- }
-
- p.example = example;
- }
-
- public void setPackageName(String packageName) {
- this.packageName = packageName;
- }
-
- public void setPackageVersion(String packageVersion) {
- this.packageVersion = packageVersion;
- }
-
public String packagePath() {
String pkgPath = packageName.replace('.', File.separatorChar);
return pythonSrcRoot + pkgPath;
}
- @Override
- public String escapeQuotationMark(String input) {
- // remove ' to avoid code injection
- return input.replace("'", "");
- }
-
- @Override
- public String escapeUnsafeCharacters(String input) {
- // remove multiline comment
- return input.replace("'''", "'_'_'");
- }
-
@Override
public String toModelImport(String name) {
String modelImport;
@@ -1008,41 +691,4 @@ public abstract class AbstractPythonConnexionServerCodegen extends DefaultCodege
vendorExtensions.put("x-modifiers", modifiers);
}
}
-
- @Override
- public void postProcessFile(File file, String fileType) {
- if (file == null) {
- return;
- }
- String pythonPostProcessFile = System.getenv("PYTHON_POST_PROCESS_FILE");
- if (StringUtils.isEmpty(pythonPostProcessFile)) {
- return; // skip if PYTHON_POST_PROCESS_FILE env variable is not defined
- }
-
- // only process files with py extension
- if ("py".equals(FilenameUtils.getExtension(file.toString()))) {
- String command = pythonPostProcessFile + " " + file.toString();
- try {
- Process p = Runtime.getRuntime().exec(command);
- int exitValue = p.waitFor();
- if (exitValue != 0) {
- LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
- } else {
- LOGGER.info("Successfully executed: " + command);
- }
- } catch (Exception e) {
- LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
- }
- }
- }
-
- /*
- * We don't want to run `escapeText` on the pattern
- * but forward it directly to the Python implementation.
- */
- @Override
- public String toRegularExpression(String pattern) {
- return addRegularExpressionDelimiter(pattern);
- }
-
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java
index 34a9f46cabc..505640121dc 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java
@@ -965,17 +965,17 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen {
example = objExample.toString();
}
// checks if the current schema has already been passed in. If so, breaks the current recursive pass
- if (seenSchemas.contains(schema)){
+ if (seenSchemas.contains(schema)) {
if (modelName != null) {
return fullPrefix + modelName + closeChars;
} else {
// this is a recursive schema
// need to add a reasonable example to avoid
// infinite recursion
- if(ModelUtils.isNullable(schema)) {
+ if (ModelUtils.isNullable(schema)) {
// if the schema is nullable, then 'None' is a valid value
return fullPrefix + "None" + closeChars;
- } else if(ModelUtils.isArraySchema(schema)) {
+ } else if (ModelUtils.isArraySchema(schema)) {
// the schema is an array, add an empty array
return fullPrefix + "[]" + closeChars;
} else {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java
index dd6fa876e06..1a79a3bc03a 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java
@@ -38,7 +38,7 @@ import java.util.regex.Pattern;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;
-public class PythonLegacyClientCodegen extends DefaultCodegen implements CodegenConfig {
+public class PythonLegacyClientCodegen extends AbstractPythonCodegen implements CodegenConfig {
private final Logger LOGGER = LoggerFactory.getLogger(PythonLegacyClientCodegen.class);
public static final String PACKAGE_URL = "packageUrl";
@@ -47,9 +47,6 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
public static final String USE_NOSE = "useNose";
public static final String RECURSION_LIMIT = "recursionLimit";
- protected String packageName = "openapi_client";
- protected String packageVersion = "1.0.0";
- protected String projectName; // for setup.py, e.g. petstore-api
protected String packageUrl;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
@@ -110,45 +107,6 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
// default HIDE_GENERATION_TIMESTAMP to true
hideGenerationTimestamp = Boolean.TRUE;
- languageSpecificPrimitives.clear();
- languageSpecificPrimitives.add("int");
- languageSpecificPrimitives.add("float");
- languageSpecificPrimitives.add("list");
- languageSpecificPrimitives.add("dict");
- languageSpecificPrimitives.add("bool");
- languageSpecificPrimitives.add("str");
- languageSpecificPrimitives.add("datetime");
- languageSpecificPrimitives.add("date");
- languageSpecificPrimitives.add("object");
- // TODO file and binary is mapped as `file`
- languageSpecificPrimitives.add("file");
- languageSpecificPrimitives.add("bytes");
-
- typeMapping.clear();
- typeMapping.put("integer", "int");
- typeMapping.put("float", "float");
- typeMapping.put("number", "float");
- typeMapping.put("long", "int");
- typeMapping.put("double", "float");
- typeMapping.put("array", "list");
- typeMapping.put("set", "list");
- typeMapping.put("map", "dict");
- typeMapping.put("boolean", "bool");
- typeMapping.put("string", "str");
- typeMapping.put("date", "date");
- typeMapping.put("DateTime", "datetime");
- typeMapping.put("object", "object");
- typeMapping.put("AnyType", "object");
- typeMapping.put("file", "file");
- // TODO binary should be mapped to byte array
- // mapped to String as a workaround
- typeMapping.put("binary", "str");
- typeMapping.put("ByteArray", "str");
- // map uuid to string for the time being
- typeMapping.put("UUID", "str");
- typeMapping.put("URI", "str");
- typeMapping.put("null", "none_type");
-
// from https://docs.python.org/3/reference/lexical_analysis.html#keywords
setReservedWordsLowerCase(
Arrays.asList(
@@ -209,10 +167,6 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
Boolean excludeTests = false;
- if (additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) {
- excludeTests = Boolean.valueOf(additionalProperties.get(CodegenConstants.EXCLUDE_TESTS).toString());
- }
-
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
}
@@ -229,15 +183,19 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION));
}
+ additionalProperties.put(CodegenConstants.PROJECT_NAME, projectName);
+ additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
+ additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
+
+ if (additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) {
+ excludeTests = Boolean.valueOf(additionalProperties.get(CodegenConstants.EXCLUDE_TESTS).toString());
+ }
+
Boolean generateSourceCodeOnly = false;
if (additionalProperties.containsKey(CodegenConstants.SOURCECODEONLY_GENERATION)) {
generateSourceCodeOnly = Boolean.valueOf(additionalProperties.get(CodegenConstants.SOURCECODEONLY_GENERATION).toString());
}
- additionalProperties.put(CodegenConstants.PROJECT_NAME, projectName);
- additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
- additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
-
if (generateSourceCodeOnly) {
// tests in /test
testFolder = packagePath() + File.separatorChar + testFolder;
@@ -260,8 +218,8 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
// check to see if setRecursionLimit is set and whether it's an integer
if (additionalProperties.containsKey(RECURSION_LIMIT)) {
try {
- Integer.parseInt((String)additionalProperties.get(RECURSION_LIMIT));
- } catch(NumberFormatException | NullPointerException e) {
+ Integer.parseInt((String) additionalProperties.get(RECURSION_LIMIT));
+ } catch (NumberFormatException | NullPointerException e) {
throw new IllegalArgumentException("recursionLimit must be an integer, e.g. 2000.");
}
}
@@ -320,15 +278,11 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
supportingFiles.add(new SupportingFile("rest.mustache", packagePath(), "rest.py"));
}
- modelPackage = packageName + "." + modelPackage;
- apiPackage = packageName + "." + apiPackage;
+ modelPackage = this.packageName + "." + modelPackage;
+ apiPackage = this.packageName + "." + apiPackage;
}
- protected static String dropDots(String str) {
- return str.replaceAll("\\.", "_");
- }
-
@Override
public String toModelImport(String name) {
String modelImport;
@@ -405,13 +359,6 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
return "Generates a Python client library.";
}
- @Override
- public String escapeReservedWord(String name) {
- if (this.reservedWordsMappings().containsKey(name)) {
- return this.reservedWordsMappings().get(name);
- }
- return "_" + name;
- }
@Override
public String apiDocFileFolder() {
@@ -467,181 +414,11 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
return outputFolder + File.separatorChar + testFolder;
}
- @Override
- public String getTypeDeclaration(Schema p) {
- if (ModelUtils.isArraySchema(p)) {
- ArraySchema ap = (ArraySchema) p;
- Schema inner = ap.getItems();
- return getSchemaType(p) + "[" + getTypeDeclaration(inner) + "]";
- } else if (ModelUtils.isMapSchema(p)) {
- Schema inner = getAdditionalProperties(p);
-
- return getSchemaType(p) + "(str, " + getTypeDeclaration(inner) + ")";
- }
- return super.getTypeDeclaration(p);
- }
-
- @Override
- public String getSchemaType(Schema p) {
- String openAPIType = super.getSchemaType(p);
- String type = null;
- if (typeMapping.containsKey(openAPIType)) {
- type = typeMapping.get(openAPIType);
- if (languageSpecificPrimitives.contains(type)) {
- return type;
- }
- } else {
- type = toModelName(openAPIType);
- }
- return type;
- }
-
- @Override
- public String toVarName(String name) {
- // sanitize name
- name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
-
- // remove dollar sign
- name = name.replaceAll("$", "");
-
- // if it's all uppper case, convert to lower case
- if (name.matches("^[A-Z_]*$")) {
- name = name.toLowerCase(Locale.ROOT);
- }
-
- // underscore the variable name
- // petId => pet_id
- name = underscore(name);
-
- // remove leading underscore
- name = name.replaceAll("^_*", "");
-
- // for reserved word or word starting with number, append _
- if (isReservedWord(name) || name.matches("^\\d.*")) {
- name = escapeReservedWord(name);
- }
-
- return name;
- }
-
- @Override
- public String toParamName(String name) {
- // to avoid conflicts with 'callback' parameter for async call
- if ("callback".equals(name)) {
- return "param_callback";
- }
-
- // should be the same as variable name
- return toVarName(name);
- }
-
- @Override
- public String toModelName(String name) {
- name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
- // remove dollar sign
- name = name.replaceAll("$", "");
-
- // model name cannot use reserved keyword, e.g. return
- if (isReservedWord(name)) {
- LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name));
- name = "model_" + name; // e.g. return => ModelReturn (after camelize)
- }
-
- // model name starts with number
- if (name.matches("^\\d.*")) {
- LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name));
- name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
- }
-
- if (!StringUtils.isEmpty(modelNamePrefix)) {
- name = modelNamePrefix + "_" + name;
- }
-
- if (!StringUtils.isEmpty(modelNameSuffix)) {
- name = name + "_" + modelNameSuffix;
- }
-
- // camelize the model name
- // phone_number => PhoneNumber
- return camelize(name);
- }
-
- @Override
- public String toModelFilename(String name) {
- // underscore the model file name
- // PhoneNumber => phone_number
- return underscore(dropDots(toModelName(name)));
- }
-
- @Override
- public String toModelTestFilename(String name) {
- return "test_" + toModelFilename(name);
- }
-
- @Override
- public String toApiFilename(String name) {
- // replace - with _ e.g. created-at => created_at
- name = name.replaceAll("-", "_");
-
- // e.g. PhoneNumberApi.py => phone_number_api.py
- return underscore(name + "_" + apiNameSuffix);
- }
-
- @Override
- public String toApiTestFilename(String name) {
- return "test_" + toApiFilename(name);
- }
-
- @Override
- public String toApiName(String name) {
- return super.toApiName(name);
- }
-
- @Override
- public String toApiVarName(String name) {
- if (name.length() == 0) {
- return "default_api";
- }
- return underscore(name + "_" + apiNameSuffix);
- }
-
- @Override
- public String toOperationId(String operationId) {
- // throw exception if method name is empty (should not occur as an auto-generated method name will be used)
- if (StringUtils.isEmpty(operationId)) {
- throw new RuntimeException("Empty method name (operationId) not allowed");
- }
-
- // method name cannot use reserved keyword, e.g. return
- if (isReservedWord(operationId)) {
- LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
- operationId = "call_" + operationId;
- }
-
- // operationId starts with a number
- if (operationId.matches("^\\d.*")) {
- LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
- operationId = "call_" + operationId;
- }
-
- return underscore(sanitizeName(operationId));
- }
-
- public void setPackageName(String packageName) {
- this.packageName = packageName;
- }
public void setUseNose(String val) {
this.useNose = Boolean.valueOf(val);
}
- public void setProjectName(String projectName) {
- this.projectName = projectName;
- }
-
- public void setPackageVersion(String packageVersion) {
- this.packageVersion = packageVersion;
- }
public void setPackageUrl(String packageUrl) {
this.packageUrl = packageUrl;
@@ -665,399 +442,4 @@ public class PythonLegacyClientCodegen extends DefaultCodegen implements Codegen
return underscore(packageName.replaceAll("[^\\w]+", ""));
}
- /**
- * Return the default value of the property
- *
- * @param p OpenAPI property object
- * @return string presentation of the default value of the property
- */
- @Override
- public String toDefaultValue(Schema p) {
- if (ModelUtils.isBooleanSchema(p)) {
- if (p.getDefault() != null) {
- if (Boolean.valueOf(p.getDefault().toString()) == false)
- return "False";
- else
- return "True";
- }
- } else if (ModelUtils.isDateSchema(p)) {
- // TODO
- } else if (ModelUtils.isDateTimeSchema(p)) {
- // TODO
- } else if (ModelUtils.isNumberSchema(p)) {
- if (p.getDefault() != null) {
- return p.getDefault().toString();
- }
- } else if (ModelUtils.isIntegerSchema(p)) {
- if (p.getDefault() != null) {
- return p.getDefault().toString();
- }
- } else if (ModelUtils.isStringSchema(p)) {
- if (p.getDefault() != null) {
- if (Pattern.compile("\r\n|\r|\n").matcher((String) p.getDefault()).find())
- return "'''" + p.getDefault() + "'''";
- else
- return "'" + ((String) p.getDefault()).replaceAll("'", "\'") + "'";
- }
- } else if (ModelUtils.isArraySchema(p)) {
- if (p.getDefault() != null) {
- return p.getDefault().toString();
- }
- }
-
- return null;
- }
-
- @Override
- public String toRegularExpression(String pattern) {
- return addRegularExpressionDelimiter(pattern);
- }
-
- @Override
- public String toExampleValue(Schema schema) {
- return toExampleValueRecursive(schema, new ArrayList(), 5);
- }
-
- private String toExampleValueRecursive(Schema schema, List included_schemas, int indentation) {
- String indentation_string = "";
- for (int i=0 ; i< indentation ; i++) indentation_string += " ";
- String example = null;
- if (schema.getExample() != null) {
- example = schema.getExample().toString();
- }
-
- if (ModelUtils.isNullType(schema) && null != example) {
- // The 'null' type is allowed in OAS 3.1 and above. It is not supported by OAS 3.0.x,
- // though this tooling supports it.
- return "None";
- }
- // correct "true"s into "True"s, since super.toExampleValue uses "toString()" on Java booleans
- if (ModelUtils.isBooleanSchema(schema) && null!=example) {
- if ("false".equalsIgnoreCase(example)) example = "False";
- else example = "True";
- }
-
- // correct "'"s into "'"s after toString()
- if (ModelUtils.isStringSchema(schema) && schema.getDefault() != null && !ModelUtils.isDateSchema(schema) && !ModelUtils.isDateTimeSchema(schema)) {
- example = (String) schema.getDefault();
- }
-
- if (StringUtils.isNotBlank(example) && !"null".equals(example)) {
- if (ModelUtils.isStringSchema(schema)) {
- example = "'" + example + "'";
- }
- return example;
- }
-
- if (schema.getEnum() != null && !schema.getEnum().isEmpty()) {
- // Enum case:
- example = schema.getEnum().get(0).toString();
- if (ModelUtils.isStringSchema(schema)) {
- example = "'" + escapeText(example) + "'";
- }
- if (null == example)
- LOGGER.warn("Empty enum. Cannot built an example!");
-
- return example;
- } else if (null != schema.get$ref()) {
- // $ref case:
- Map allDefinitions = ModelUtils.getSchemas(this.openAPI);
- String ref = ModelUtils.getSimpleRef(schema.get$ref());
- if (allDefinitions != null) {
- Schema refSchema = allDefinitions.get(ref);
- if (null == refSchema) {
- return "None";
- } else {
- String refTitle = refSchema.getTitle();
- if (StringUtils.isBlank(refTitle) || "null".equals(refTitle)) {
- refSchema.setTitle(ref);
- }
- if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
- included_schemas.add(schema.getTitle());
- }
- return toExampleValueRecursive(refSchema, included_schemas, indentation);
- }
- } else {
- LOGGER.warn("allDefinitions not defined in toExampleValue!\n");
- }
- }
- if (ModelUtils.isDateSchema(schema)) {
- example = "datetime.datetime.strptime('1975-12-30', '%Y-%m-%d').date()";
- return example;
- } else if (ModelUtils.isDateTimeSchema(schema)) {
- example = "datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f')";
- return example;
- } else if (ModelUtils.isBinarySchema(schema)) {
- example = "bytes(b'blah')";
- return example;
- } else if (ModelUtils.isByteArraySchema(schema)) {
- example = "YQ==";
- } else if (ModelUtils.isStringSchema(schema)) {
- // a BigDecimal:
- if ("Number".equalsIgnoreCase(schema.getFormat())) {return "1";}
- if (StringUtils.isNotBlank(schema.getPattern())) {
- String pattern = schema.getPattern();
- RgxGen rgxGen = new RgxGen(patternCorrection(pattern));
- // this seed makes it so if we have [a-z] we pick a
- Random random = new Random(18);
- String sample = rgxGen.generate(random);
- // omit leading / and trailing /, omit trailing /i
- Pattern valueExtractor = Pattern.compile("^/\\^?(.+?)\\$?/.?$");
- Matcher m = valueExtractor.matcher(sample);
- if (m.find()) {
- example = m.group(m.groupCount());
- } else {
- example = sample;
- }
- }
- if (example == null) {
- example = "";
- }
- int len = 0;
- if (null != schema.getMinLength()) {
- len = schema.getMinLength().intValue();
- if (len < 1) {
- example = "";
- } else {
- for (int i=0;i reqs = schema.getRequired();
-
- // if required and optionals
- List reqs = new ArrayList<>();
- if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
- for (Object toAdd : schema.getProperties().keySet()) {
- reqs.add((String) toAdd);
- }
-
- Map properties = schema.getProperties();
- Set propkeys = null;
- if (properties != null) propkeys = properties.keySet();
- if (toExclude != null && reqs.contains(toExclude)) {
- reqs.remove(toExclude);
- }
- for (String toRemove : included_schemas) {
- if (reqs.contains(toRemove)) {
- reqs.remove(toRemove);
- }
- }
- if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
- included_schemas.add(schema.getTitle());
- }
- if (null != schema.getRequired()) for (Object toAdd : schema.getRequired()) {
- reqs.add((String) toAdd);
- }
- if (null != propkeys) for (String propname : propkeys) {
- Schema schema2 = properties.get(propname);
- if (reqs.contains(propname)) {
- String refTitle = schema2.getTitle();
- if (StringUtils.isBlank(refTitle) || "null".equals(refTitle)) {
- schema2.setTitle(propname);
- }
- example += "\n" + indentation_string + underscore(propname) + " = " +
- toExampleValueRecursive(schema2, included_schemas, indentation + 1) + ", ";
- }
- }
- }
- example +=")";
- } else {
- LOGGER.warn("Type " + schema.getType() + " not handled properly in toExampleValue");
- }
-
- if (ModelUtils.isStringSchema(schema)) {
- example = "'" + escapeText(example) + "'";
- }
-
- return example;
- }
-
- @Override
- public void setParameterExampleValue(CodegenParameter p) {
- String example;
-
- if (p.defaultValue == null) {
- example = p.example;
- } else {
- p.example = p.defaultValue;
- return;
- }
-
- String type = p.baseType;
- if (type == null) {
- type = p.dataType;
- }
-
- if ("String".equalsIgnoreCase(type) || "str".equalsIgnoreCase(type)) {
- if (example == null) {
- example = p.paramName + "_example";
- }
- example = "'" + escapeText(example) + "'";
- } else if ("Integer".equals(type) || "int".equals(type)) {
- if (example == null) {
- example = "56";
- }
- } else if ("Float".equalsIgnoreCase(type) || "Double".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "3.4";
- }
- } else if ("BOOLEAN".equalsIgnoreCase(type) || "bool".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "True";
- }
- } else if ("file".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "/path/to/file";
- }
- example = "'" + escapeText(example) + "'";
- } else if ("Date".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "2013-10-20";
- }
- example = "'" + escapeText(example) + "'";
- } else if ("DateTime".equalsIgnoreCase(type)) {
- if (example == null) {
- example = "2013-10-20T19:20:30+01:00";
- }
- example = "'" + escapeText(example) + "'";
- } else if (!languageSpecificPrimitives.contains(type)) {
- // type is a model class, e.g. User
- example = this.packageName + "." + type + "()";
- } else {
- LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
- }
-
- if (example == null) {
- example = "None";
- } else if (Boolean.TRUE.equals(p.isArray)) {
- example = "[" + example + "]";
- } else if (Boolean.TRUE.equals(p.isMap)) {
- example = "{'key': " + example + "}";
- }
-
- p.example = example;
- }
-
- @Override
- public void setParameterExampleValue(CodegenParameter codegenParameter, Parameter parameter) {
- Schema schema = parameter.getSchema();
-
- if (parameter.getExample() != null) {
- codegenParameter.example = parameter.getExample().toString();
- } else if (parameter.getExamples() != null && !parameter.getExamples().isEmpty()) {
- Example example = parameter.getExamples().values().iterator().next();
- if (example.getValue() != null) {
- codegenParameter.example = example.getValue().toString();
- }
- } else if (schema != null && schema.getExample() != null) {
- codegenParameter.example = schema.getExample().toString();
- }
-
- setParameterExampleValue(codegenParameter);
- }
-
- @Override
- public String sanitizeTag(String tag) {
- return sanitizeName(tag);
- }
-
- @Override
- public String escapeQuotationMark(String input) {
- // remove ' to avoid code injection
- return input.replace("'", "");
- }
-
- @Override
- public String escapeUnsafeCharacters(String input) {
- // remove multiline comment
- return input.replace("'''", "'_'_'");
- }
-
- @Override
- public void postProcessFile(File file, String fileType) {
- if (file == null) {
- return;
- }
- String pythonPostProcessFile = System.getenv("PYTHON_POST_PROCESS_FILE");
- if (StringUtils.isEmpty(pythonPostProcessFile)) {
- return; // skip if PYTHON_POST_PROCESS_FILE env variable is not defined
- }
-
- // only process files with py extension
- if ("py".equals(FilenameUtils.getExtension(file.toString()))) {
- String command = pythonPostProcessFile + " " + file.toString();
- try {
- Process p = Runtime.getRuntime().exec(command);
- int exitValue = p.waitFor();
- if (exitValue != 0) {
- LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
- } else {
- LOGGER.info("Successfully executed: " + command);
- }
- } catch (Exception e) {
- LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
- }
- }
- }
-
- public String patternCorrection(String pattern){
- // Java does not recognize starting and ending forward slashes and mode modifiers
- // It considers them as characters with no special meaning and tries to find them in the match string
- boolean checkEnding = pattern.endsWith("/i") || pattern.endsWith("/g") || pattern.endsWith("/m");
- if (checkEnding) pattern = pattern.substring(0, pattern.length()-2);
- if (pattern.endsWith("/")) pattern = pattern.substring(0, pattern.length()-1);
- if (pattern.startsWith("/")) pattern = pattern.substring(1);
- return pattern;
- }
}
diff --git a/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/openapi/openapi.yaml b/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/openapi/openapi.yaml
index 1e68be278ed..57d23de03cf 100644
--- a/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/openapi/openapi.yaml
+++ b/samples/server/petstore/python-aiohttp-srclayout/src/openapi_server/openapi/openapi.yaml
@@ -619,15 +619,19 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
petId:
format: int64
+ title: petId
type: integer
quantity:
format: int32
+ title: quantity
type: integer
shipDate:
format: date-time
+ title: shipDate
type: string
status:
description: Order Status
@@ -635,9 +639,11 @@ components:
- placed
- approved
- delivered
+ title: status
type: string
complete:
default: false
+ title: complete
type: boolean
title: Pet Order
type: object
@@ -651,8 +657,10 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
name:
+ title: name
type: string
title: Pet category
type: object
@@ -701,8 +709,10 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
name:
+ title: name
type: string
title: Pet Tag
type: object
@@ -771,10 +781,13 @@ components:
properties:
code:
format: int32
+ title: code
type: integer
type:
+ title: type
type: string
message:
+ title: message
type: string
title: An uploaded response
type: object
diff --git a/samples/server/petstore/python-aiohttp/openapi_server/openapi/openapi.yaml b/samples/server/petstore/python-aiohttp/openapi_server/openapi/openapi.yaml
index 1e68be278ed..57d23de03cf 100644
--- a/samples/server/petstore/python-aiohttp/openapi_server/openapi/openapi.yaml
+++ b/samples/server/petstore/python-aiohttp/openapi_server/openapi/openapi.yaml
@@ -619,15 +619,19 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
petId:
format: int64
+ title: petId
type: integer
quantity:
format: int32
+ title: quantity
type: integer
shipDate:
format: date-time
+ title: shipDate
type: string
status:
description: Order Status
@@ -635,9 +639,11 @@ components:
- placed
- approved
- delivered
+ title: status
type: string
complete:
default: false
+ title: complete
type: boolean
title: Pet Order
type: object
@@ -651,8 +657,10 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
name:
+ title: name
type: string
title: Pet category
type: object
@@ -701,8 +709,10 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
name:
+ title: name
type: string
title: Pet Tag
type: object
@@ -771,10 +781,13 @@ components:
properties:
code:
format: int32
+ title: code
type: integer
type:
+ title: type
type: string
message:
+ title: message
type: string
title: An uploaded response
type: object
diff --git a/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml b/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml
index 0edb89eac95..f8b70b3930b 100644
--- a/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml
+++ b/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml
@@ -608,15 +608,19 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
petId:
format: int64
+ title: petId
type: integer
quantity:
format: int32
+ title: quantity
type: integer
shipDate:
format: date-time
+ title: shipDate
type: string
status:
description: Order Status
@@ -624,9 +628,11 @@ components:
- placed
- approved
- delivered
+ title: status
type: string
complete:
default: false
+ title: complete
type: boolean
title: Pet Order
type: object
@@ -640,8 +646,10 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
name:
+ title: name
type: string
title: Pet category
type: object
@@ -690,8 +698,10 @@ components:
properties:
id:
format: int64
+ title: id
type: integer
name:
+ title: name
type: string
title: Pet Tag
type: object
@@ -760,10 +770,13 @@ components:
properties:
code:
format: int32
+ title: code
type: integer
type:
+ title: type
type: string
message:
+ title: message
type: string
title: An uploaded response
type: object