forked from loafle/openapi-generator-original
[Refactor] create Python abstract class (#8817)
* create python abstract base class * refactor AbstractPythonConnexionServerCodegen * update doc
This commit is contained in:
@@ -42,13 +42,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>Dict</li>
|
||||
<li>List</li>
|
||||
<li>bool</li>
|
||||
<li>byte</li>
|
||||
<li>bytearray</li>
|
||||
<li>bytes</li>
|
||||
<li>date</li>
|
||||
<li>datetime</li>
|
||||
<li>dict</li>
|
||||
<li>file</li>
|
||||
<li>float</li>
|
||||
<li>int</li>
|
||||
<li>list</li>
|
||||
<li>object</li>
|
||||
<li>str</li>
|
||||
</ul>
|
||||
@@ -56,9 +57,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
## RESERVED WORDS
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>all_params</li>
|
||||
<li>and</li>
|
||||
<li>as</li>
|
||||
<li>assert</li>
|
||||
<li>async</li>
|
||||
<li>auth_settings</li>
|
||||
<li>await</li>
|
||||
<li>body_params</li>
|
||||
<li>break</li>
|
||||
<li>class</li>
|
||||
<li>continue</li>
|
||||
@@ -71,21 +77,27 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>false</li>
|
||||
<li>finally</li>
|
||||
<li>for</li>
|
||||
<li>form_params</li>
|
||||
<li>from</li>
|
||||
<li>global</li>
|
||||
<li>header_params</li>
|
||||
<li>if</li>
|
||||
<li>import</li>
|
||||
<li>in</li>
|
||||
<li>is</li>
|
||||
<li>lambda</li>
|
||||
<li>local_var_files</li>
|
||||
<li>none</li>
|
||||
<li>nonlocal</li>
|
||||
<li>not</li>
|
||||
<li>or</li>
|
||||
<li>pass</li>
|
||||
<li>path_params</li>
|
||||
<li>print</li>
|
||||
<li>property</li>
|
||||
<li>query_params</li>
|
||||
<li>raise</li>
|
||||
<li>resource_path</li>
|
||||
<li>return</li>
|
||||
<li>self</li>
|
||||
<li>true</li>
|
||||
|
||||
@@ -42,13 +42,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>Dict</li>
|
||||
<li>List</li>
|
||||
<li>bool</li>
|
||||
<li>byte</li>
|
||||
<li>bytearray</li>
|
||||
<li>bytes</li>
|
||||
<li>date</li>
|
||||
<li>datetime</li>
|
||||
<li>dict</li>
|
||||
<li>file</li>
|
||||
<li>float</li>
|
||||
<li>int</li>
|
||||
<li>list</li>
|
||||
<li>object</li>
|
||||
<li>str</li>
|
||||
</ul>
|
||||
@@ -56,9 +57,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
## RESERVED WORDS
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>all_params</li>
|
||||
<li>and</li>
|
||||
<li>as</li>
|
||||
<li>assert</li>
|
||||
<li>async</li>
|
||||
<li>auth_settings</li>
|
||||
<li>await</li>
|
||||
<li>body_params</li>
|
||||
<li>break</li>
|
||||
<li>class</li>
|
||||
<li>continue</li>
|
||||
@@ -71,21 +77,27 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>false</li>
|
||||
<li>finally</li>
|
||||
<li>for</li>
|
||||
<li>form_params</li>
|
||||
<li>from</li>
|
||||
<li>global</li>
|
||||
<li>header_params</li>
|
||||
<li>if</li>
|
||||
<li>import</li>
|
||||
<li>in</li>
|
||||
<li>is</li>
|
||||
<li>lambda</li>
|
||||
<li>local_var_files</li>
|
||||
<li>none</li>
|
||||
<li>nonlocal</li>
|
||||
<li>not</li>
|
||||
<li>or</li>
|
||||
<li>pass</li>
|
||||
<li>path_params</li>
|
||||
<li>print</li>
|
||||
<li>property</li>
|
||||
<li>query_params</li>
|
||||
<li>raise</li>
|
||||
<li>resource_path</li>
|
||||
<li>return</li>
|
||||
<li>self</li>
|
||||
<li>true</li>
|
||||
|
||||
@@ -42,13 +42,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>Dict</li>
|
||||
<li>List</li>
|
||||
<li>bool</li>
|
||||
<li>byte</li>
|
||||
<li>bytearray</li>
|
||||
<li>bytes</li>
|
||||
<li>date</li>
|
||||
<li>datetime</li>
|
||||
<li>dict</li>
|
||||
<li>file</li>
|
||||
<li>float</li>
|
||||
<li>int</li>
|
||||
<li>list</li>
|
||||
<li>object</li>
|
||||
<li>str</li>
|
||||
</ul>
|
||||
@@ -56,9 +57,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
## RESERVED WORDS
|
||||
|
||||
<ul class="column-ul">
|
||||
<li>all_params</li>
|
||||
<li>and</li>
|
||||
<li>as</li>
|
||||
<li>assert</li>
|
||||
<li>async</li>
|
||||
<li>auth_settings</li>
|
||||
<li>await</li>
|
||||
<li>body_params</li>
|
||||
<li>break</li>
|
||||
<li>class</li>
|
||||
<li>continue</li>
|
||||
@@ -71,21 +77,27 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>false</li>
|
||||
<li>finally</li>
|
||||
<li>for</li>
|
||||
<li>form_params</li>
|
||||
<li>from</li>
|
||||
<li>global</li>
|
||||
<li>header_params</li>
|
||||
<li>if</li>
|
||||
<li>import</li>
|
||||
<li>in</li>
|
||||
<li>is</li>
|
||||
<li>lambda</li>
|
||||
<li>local_var_files</li>
|
||||
<li>none</li>
|
||||
<li>nonlocal</li>
|
||||
<li>not</li>
|
||||
<li>or</li>
|
||||
<li>pass</li>
|
||||
<li>path_params</li>
|
||||
<li>print</li>
|
||||
<li>property</li>
|
||||
<li>query_params</li>
|
||||
<li>raise</li>
|
||||
<li>resource_path</li>
|
||||
<li>return</li>
|
||||
<li>self</li>
|
||||
<li>true</li>
|
||||
|
||||
@@ -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<String>(), 5);
|
||||
}
|
||||
|
||||
private String toExampleValueRecursive(Schema schema, List<String> 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<String, Schema> 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<String> reqs = schema.getRequired();
|
||||
|
||||
// if required and optionals
|
||||
List<String> reqs = new ArrayList<>();
|
||||
if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
|
||||
for (Object toAdd : schema.getProperties().keySet()) {
|
||||
reqs.add((String) toAdd);
|
||||
}
|
||||
|
||||
Map<String, Schema> properties = schema.getProperties();
|
||||
Set<String> 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("\\.", "_");
|
||||
}
|
||||
}
|
||||
@@ -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<Character, String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 <package>/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<String>(), 5);
|
||||
}
|
||||
|
||||
private String toExampleValueRecursive(Schema schema, List<String> 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<String, Schema> 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<String> reqs = schema.getRequired();
|
||||
|
||||
// if required and optionals
|
||||
List<String> reqs = new ArrayList<>();
|
||||
if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
|
||||
for (Object toAdd : schema.getProperties().keySet()) {
|
||||
reqs.add((String) toAdd);
|
||||
}
|
||||
|
||||
Map<String, Schema> properties = schema.getProperties();
|
||||
Set<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user