Skip to content

Commit

Permalink
#3: The generator supports inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
bednar committed Aug 12, 2019
1 parent e56fb85 commit 8b3ad9b
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 1 deletion.
2 changes: 1 addition & 1 deletion openapi-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<openapi-generator-version>4.0.2</openapi-generator-version>
<openapi-generator-version>3.3.4</openapi-generator-version>
<maven-plugin-version>1.0.0</maven-plugin-version>
<junit-version>4.8.1</junit-version>
</properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package org.influxdata.codegen;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;

import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.languages.PythonClientCodegen;

import static org.openapitools.codegen.utils.StringUtils.camelize;
Expand Down Expand Up @@ -53,6 +60,36 @@ public void processOpts() {
.collect(Collectors.toList());
}

@Override
public CodegenModel fromModel(final String name, final Schema model, final Map<String, Schema> allDefinitions) {
CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);

return codegenModel;
}

@Override
public Map<String, Object> postProcessAllModels(final Map<String, Object> models) {

Map<String, Object> allModels = super.postProcessAllModels(models);

for (Map.Entry<String, Object> entry : allModels.entrySet()) {

String modelName = entry.getKey();
Object modelConfig = entry.getValue();

CodegenModel model = getModel((HashMap) modelConfig);

if (model.getParent() != null) {
CodegenModel parentModel = getModel((HashMap) allModels.get(model.getParent()));
model.vendorExtensions.put("x-parent-classFilename", parentModel.getClassFilename());
model.vendorExtensions.put("x-has-parent-vars", Boolean.TRUE);
model.vendorExtensions.put("x-parent-vars", parentModel.getVars());
}
}

return allModels;
}

@Override
public String toApiName(String name) {
if (name.length() == 0) {
Expand All @@ -79,4 +116,12 @@ public String toApiFilename(String name) {
// e.g. PhoneNumberService.py => phone_number_service.py
return underscore(name) + "_service";
}

@Nonnull
private CodegenModel getModel(@Nonnull final HashMap modelConfig) {

HashMap models = (HashMap) ((ArrayList) modelConfig.get("models")).get(0);

return (CodegenModel) models.get("model");
}
}
240 changes: 240 additions & 0 deletions openapi-generator/src/main/resources/python/model.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
# coding: utf-8

{{>partial_header}}

import pprint
import re # noqa: F401

import six
{{#models}}
{{#model}}
{{#parent}}
from influxdb2.domain.{{{vendorExtensions.x-parent-classFilename}}} import {{{parent}}}
{{/parent}}
{{/model}}
{{/models}}


{{#models}}
{{#model}}
class {{classname}}({{#parent}}{{{parent}}}{{/parent}}{{^parent}}object{{/parent}}):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech

Do not edit the class manually.
"""{{#allowableValues}}

"""
allowed enum values
"""
{{#enumVars}}
{{name}} = {{{value}}}{{^-last}}
{{/-last}}
{{/enumVars}}{{/allowableValues}}

"""
Attributes:
openapi_types (dict): The key is attribute name
and the value is attribute type.
attribute_map (dict): The key is attribute name
and the value is json key in definition.
"""
openapi_types = {
{{#vars}}
'{{name}}': '{{{dataType}}}'{{#hasMore}},{{/hasMore}}{{^hasMore}}{{#model.vendorExtensions.x-has-parent-vars}},{{/model.vendorExtensions.x-has-parent-vars}}{{/hasMore}}
{{/vars}}
{{#vendorExtensions.x-parent-vars}}
'{{name}}': '{{{dataType}}}'{{#hasMore}},{{/hasMore}}
{{/vendorExtensions.x-parent-vars}}
}

attribute_map = {
{{#vars}}
'{{name}}': '{{baseName}}'{{#hasMore}},{{/hasMore}}{{^hasMore}}{{#model.vendorExtensions.x-has-parent-vars}},{{/model.vendorExtensions.x-has-parent-vars}}{{/hasMore}}
{{/vars}}
{{#vendorExtensions.x-parent-vars}}
'{{name}}': '{{baseName}}'{{#hasMore}},{{/hasMore}}
{{/vendorExtensions.x-parent-vars}}
}
{{#discriminator}}

discriminator_value_class_map = {
{{#children}}'{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}': '{{{classname}}}'{{^-last}},
{{/-last}}{{/children}}
}
{{/discriminator}}

def __init__(self{{#vars}}, {{name}}={{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}None{{/defaultValue}}{{/vars}}{{#vendorExtensions.x-parent-vars}}, {{name}}={{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}None{{/defaultValue}}{{/vendorExtensions.x-parent-vars}}): # noqa: E501
"""{{classname}} - a model defined in OpenAPI""" # noqa: E501
{{#parent}}
{{{parent}}}.__init__(self{{#vendorExtensions.x-parent-vars}}, {{name}}={{name}}{{/vendorExtensions.x-parent-vars}})
{{/parent}}
{{#vars}}{{#-first}}
{{/-first}}
self._{{name}} = None
{{/vars}}
self.discriminator = {{#discriminator}}'{{{discriminatorName}}}'{{/discriminator}}{{^discriminator}}None{{/discriminator}}
{{#vars}}{{#-first}}
{{/-first}}
{{#required}}
self.{{name}} = {{name}}
{{/required}}
{{^required}}
{{#isNullable}}
self.{{name}} = {{name}}
{{/isNullable}}
{{^isNullable}}
if {{name}} is not None:
self.{{name}} = {{name}}
{{/isNullable}}
{{/required}}
{{/vars}}

{{#vars}}
@property
def {{name}}(self):
"""Gets the {{name}} of this {{classname}}. # noqa: E501

{{#description}}
{{{description}}} # noqa: E501
{{/description}}

:return: The {{name}} of this {{classname}}. # noqa: E501
:rtype: {{dataType}}
"""
return self._{{name}}

@{{name}}.setter
def {{name}}(self, {{name}}):
"""Sets the {{name}} of this {{classname}}.

{{#description}}
{{{description}}} # noqa: E501
{{/description}}

:param {{name}}: The {{name}} of this {{classname}}. # noqa: E501
:type: {{dataType}}
"""
{{^isNullable}}
{{#required}}
if {{name}} is None:
raise ValueError("Invalid value for `{{name}}`, must not be `None`") # noqa: E501
{{/required}}
{{/isNullable}}
{{#isEnum}}
{{#isContainer}}
allowed_values = [{{#isNullable}}None,{{/isNullable}}{{#allowableValues}}{{#values}}{{#items.isString}}"{{/items.isString}}{{{this}}}{{#items.isString}}"{{/items.isString}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] # noqa: E501
{{#isListContainer}}
if not set({{{name}}}).issubset(set(allowed_values)):
raise ValueError(
"Invalid values for `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501
.format(", ".join(map(str, set({{{name}}}) - set(allowed_values))), # noqa: E501
", ".join(map(str, allowed_values)))
)
{{/isListContainer}}
{{#isMapContainer}}
if not set({{{name}}}.keys()).issubset(set(allowed_values)):
raise ValueError(
"Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501
.format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501
", ".join(map(str, allowed_values)))
)
{{/isMapContainer}}
{{/isContainer}}
{{^isContainer}}
allowed_values = [{{#isNullable}}None,{{/isNullable}}{{#allowableValues}}{{#values}}{{#isString}}"{{/isString}}{{{this}}}{{#isString}}"{{/isString}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] # noqa: E501
if {{{name}}} not in allowed_values:
raise ValueError(
"Invalid value for `{{{name}}}` ({0}), must be one of {1}" # noqa: E501
.format({{{name}}}, allowed_values)
)
{{/isContainer}}
{{/isEnum}}
{{^isEnum}}
{{#hasValidation}}
{{#maxLength}}
if {{name}} is not None and len({{name}}) > {{maxLength}}:
raise ValueError("Invalid value for `{{name}}`, length must be less than or equal to `{{maxLength}}`") # noqa: E501
{{/maxLength}}
{{#minLength}}
if {{name}} is not None and len({{name}}) < {{minLength}}:
raise ValueError("Invalid value for `{{name}}`, length must be greater than or equal to `{{minLength}}`") # noqa: E501
{{/minLength}}
{{#maximum}}
if {{name}} is not None and {{name}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}: # noqa: E501
raise ValueError("Invalid value for `{{name}}`, must be a value less than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}`{{maximum}}`") # noqa: E501
{{/maximum}}
{{#minimum}}
if {{name}} is not None and {{name}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}: # noqa: E501
raise ValueError("Invalid value for `{{name}}`, must be a value greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}`{{minimum}}`") # noqa: E501
{{/minimum}}
{{#pattern}}
if {{name}} is not None and not re.search(r'{{{vendorExtensions.x-regex}}}', {{name}}{{#vendorExtensions.x-modifiers}}{{#-first}}, flags={{/-first}}re.{{.}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}): # noqa: E501
raise ValueError(r"Invalid value for `{{name}}`, must be a follow pattern or equal to `{{{pattern}}}`") # noqa: E501
{{/pattern}}
{{#maxItems}}
if {{name}} is not None and len({{name}}) > {{maxItems}}:
raise ValueError("Invalid value for `{{name}}`, number of items must be less than or equal to `{{maxItems}}`") # noqa: E501
{{/maxItems}}
{{#minItems}}
if {{name}} is not None and len({{name}}) < {{minItems}}:
raise ValueError("Invalid value for `{{name}}`, number of items must be greater than or equal to `{{minItems}}`") # noqa: E501
{{/minItems}}
{{/hasValidation}}
{{/isEnum}}

self._{{name}} = {{name}}

{{/vars}}
{{#discriminator}}
def get_real_child_model(self, data):
"""Returns the real base class specified by the discriminator"""
discriminator_key = self.attribute_map[self.discriminator]
discriminator_value = data[discriminator_key]
return self.discriminator_value_class_map.get(discriminator_value)

{{/discriminator}}
def to_dict(self):
"""Returns the model properties as a dict"""
result = {}

for attr, _ in six.iteritems(self.openapi_types):
value = getattr(self, attr)
if isinstance(value, list):
result[attr] = list(map(
lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
value
))
elif hasattr(value, "to_dict"):
result[attr] = value.to_dict()
elif isinstance(value, dict):
result[attr] = dict(map(
lambda item: (item[0], item[1].to_dict())
if hasattr(item[1], "to_dict") else item,
value.items()
))
else:
result[attr] = value

return result

def to_str(self):
"""Returns the string representation of the model"""
return pprint.pformat(self.to_dict())

def __repr__(self):
"""For `print` and `pprint`"""
return self.to_str()

def __eq__(self, other):
"""Returns true if both objects are equal"""
if not isinstance(other, {{classname}}):
return False

return self.__dict__ == other.__dict__

def __ne__(self, other):
"""Returns true if both objects are not equal"""
return not self == other
{{/model}}
{{/models}}

0 comments on commit 8b3ad9b

Please sign in to comment.