Add a new Python client generator - python-nextgen (#14157)

* add python-nextgen generator

* remove client_side_validation from model

* remove configuraiton import from models

* add inheritance support

* update test requirements, tox

* add typings, pydanic to models

* add test model

* minor improvements

* add enum support

* add typing for parameters, remove validations

* add oneof, anyof support

* fix default value

* fix deserialization, api tests passed

* private variable naming, update tests, all tests passed

* remove six

* remove nose

* update doc

* remove sortParamsByRequiredFlag option

* add parameter validation

* add validation tests

* simplify Field()

* remove previous required parameter validation

* improve parameter handling

* support discriminator mapping

* better typing discriminator mapping

* format test code

* fix tests

* fix oneOf from_dict, add test

* add set validation test

* fix nested oneof serialization, add tests

* add model import

* remove models. prefix

* remove import models

* remove model import from api

* simplify from_dict

* add typing for return

* skip pydantic import in return type

* fix tests, fix enum

* restore more enum schema tests

* uncomment enum integer test

* clean up getfullargspec import in model

* clean up getfullargspec import

* fix deserilizatoin for nested oneof

* minor fixes, add tests

* fix regular expression

* add aiohttp samples, add tests

* remove default content type to json

* update template

* fix select accept, content-type

* move tests

* move tests

* fix url query parameters

* fix list

* fix samples

* fix param pydantic, add list as reserved word

* fix auto-generated doc

* fix readme

* fix list, fix special variable name with var_

* fix Literal in python 3.7

* fix default configuration

* fix aiohttp tests

* set default api client instance

* deprecate get_default_copy method

* fix enum model

* fix enum serializatio/deserialization

* add github workflow support

* add regular expression validator

* add enum validator

* better model import

* fix file, remove x-py-import-models

* rename local var

* better model example

* fix regular expression warning, add special_name test, whitelist schema

* skip self import

* update samples

* various fixes

* add base64, json as reserved word

* add http signature support

* add http signature test

* add additioanl properties support in python client

* add decimal support

* use strictstr instead of constr

* fix test with virtualenv

* add nullable support

* add readonly support

* add model name caching

* fix circular reference import

* add onelook discriminator lookup

* add tests

* update samples

* fix locale

* Fix client legacy generator asyncio README code example

* test python-nextgen in circleci

* fix pom.xml

* update python to 3.7.15

* test with python 3.7.12

* various updates

* fix python legacy
This commit is contained in:
William Cheng
2022-12-17 16:05:47 +08:00
committed by GitHub
parent 6800905123
commit 0cf5ed619d
568 changed files with 56832 additions and 272 deletions

View File

@@ -53,9 +53,9 @@ elif [ "$NODE_INDEX" = "3" ]; then
#./configure --enable-optimizations
#sudo make altinstall
pyenv install --list
pyenv install 3.6.3
pyenv install 3.7.12
pyenv install 2.7.14
pyenv global 3.6.3
pyenv global 3.7.12
# Install node@stable (for angular 6)
set +e

View File

@@ -0,0 +1,7 @@
generatorName: python-nextgen
outputDir: samples/openapi3/client/petstore/python-nextgen-aiohttp
inputSpec: modules/openapi-generator/src/test/resources/3_0/python/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/python-nextgen
library: asyncio
additionalProperties:
packageName: petstore_api

View File

@@ -0,0 +1,8 @@
generatorName: python-nextgen
outputDir: samples/openapi3/client/petstore/python-nextgen
inputSpec: modules/openapi-generator/src/test/resources/3_0/python/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/python-nextgen
additionalProperties:
packageName: petstore_api
useOneOfDiscriminatorLookup: "true"
disallowAdditionalPropertiesIfNotPresent: false

View File

@@ -52,6 +52,7 @@ The following generators are available:
* [powershell (beta)](generators/powershell.md)
* [python](generators/python.md)
* [python-legacy](generators/python-legacy.md)
* [python-nextgen (beta)](generators/python-nextgen.md)
* [python-prior](generators/python-prior.md)
* [r](generators/r.md)
* [ruby](generators/ruby.md)

View File

@@ -45,6 +45,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>Dict</li>
<li>List</li>
<li>bool</li>
<li>bytes</li>
<li>date</li>

View File

@@ -0,0 +1,225 @@
---
title: Documentation for the python-nextgen Generator
---
## METADATA
| Property | Value | Notes |
| -------- | ----- | ----- |
| generator name | python-nextgen | pass this to the generate command after -g |
| generator stability | BETA | |
| generator type | CLIENT | |
| generator language | Python | |
| generator language version | 3.7+ | |
| generator default templating engine | mustache | |
| helpTxt | Generates a Python client library. | |
## CONFIG OPTIONS
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.</dd></dl>|true|
|generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|library|library template (sub-template) to use: asyncio, tornado (deprecated), urllib3| |urllib3|
|packageName|python package name (convention: snake_case).| |openapi_client|
|packageUrl|python package URL.| |null|
|packageVersion|python package version.| |1.0.0|
|projectName|python project name in setup.py (e.g. petstore-api).| |null|
|recursionLimit|Set the recursion limit. If not set, use the system default value.| |null|
## IMPORT MAPPING
| Type/Alias | Imports |
| ---------- | ------- |
## INSTANTIATION TYPES
| Type/Alias | Instantiated By |
| ---------- | --------------- |
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>Dict</li>
<li>List</li>
<li>bool</li>
<li>bytes</li>
<li>date</li>
<li>datetime</li>
<li>decimal.Decimal</li>
<li>dict</li>
<li>float</li>
<li>int</li>
<li>list</li>
<li>object</li>
<li>str</li>
</ul>
## RESERVED WORDS
<ul class="column-ul">
<li>and</li>
<li>as</li>
<li>assert</li>
<li>async</li>
<li>await</li>
<li>base64</li>
<li>break</li>
<li>class</li>
<li>continue</li>
<li>date</li>
<li>def</li>
<li>del</li>
<li>elif</li>
<li>else</li>
<li>except</li>
<li>exec</li>
<li>false</li>
<li>finally</li>
<li>for</li>
<li>from</li>
<li>global</li>
<li>if</li>
<li>import</li>
<li>in</li>
<li>is</li>
<li>json</li>
<li>lambda</li>
<li>none</li>
<li>nonlocal</li>
<li>not</li>
<li>or</li>
<li>pass</li>
<li>print</li>
<li>property</li>
<li>raise</li>
<li>return</li>
<li>schema</li>
<li>self</li>
<li>true</li>
<li>try</li>
<li>while</li>
<li>with</li>
<li>yield</li>
</ul>
## FEATURE SET
### Client Modification Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasePath|✗|ToolingExtension
|Authorizations|✗|ToolingExtension
|UserAgent|✗|ToolingExtension
|MockServer|✗|ToolingExtension
### Data Type Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Custom|✗|OAS2,OAS3
|Int32|✓|OAS2,OAS3
|Int64|✓|OAS2,OAS3
|Float|✓|OAS2,OAS3
|Double|✓|OAS2,OAS3
|Decimal|✓|ToolingExtension
|String|✓|OAS2,OAS3
|Byte|✓|OAS2,OAS3
|Binary|✓|OAS2,OAS3
|Boolean|✓|OAS2,OAS3
|Date|✓|OAS2,OAS3
|DateTime|✓|OAS2,OAS3
|Password|✓|OAS2,OAS3
|File|✓|OAS2
|Uuid|✗|
|Array|✓|OAS2,OAS3
|Null|✗|OAS3
|AnyType|✗|OAS2,OAS3
|Object|✓|OAS2,OAS3
|Maps|✓|ToolingExtension
|CollectionFormat|✓|OAS2
|CollectionFormatMulti|✓|OAS2
|Enum|✓|OAS2,OAS3
|ArrayOfEnum|✓|ToolingExtension
|ArrayOfModel|✓|ToolingExtension
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|ArrayOfCollectionOfModel|✓|ToolingExtension
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|MapOfEnum|✓|ToolingExtension
|MapOfModel|✓|ToolingExtension
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|MapOfCollectionOfModel|✓|ToolingExtension
|MapOfCollectionOfEnum|✓|ToolingExtension
### Documentation Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Readme|✓|ToolingExtension
|Model|✓|ToolingExtension
|Api|✓|ToolingExtension
### Global Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Host|✓|OAS2,OAS3
|BasePath|✓|OAS2,OAS3
|Info|✓|OAS2,OAS3
|Schemes|✗|OAS2,OAS3
|PartialSchemes|✓|OAS2,OAS3
|Consumes|✓|OAS2
|Produces|✓|OAS2
|ExternalDocumentation|✓|OAS2,OAS3
|Examples|✓|OAS2,OAS3
|XMLStructureDefinitions|✗|OAS2,OAS3
|MultiServer|✗|OAS3
|ParameterizedServer|✗|OAS3
|ParameterStyling|✗|OAS3
|Callbacks|✗|OAS3
|LinkObjects|✗|OAS3
### Parameter Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Path|✓|OAS2,OAS3
|Query|✓|OAS2,OAS3
|Header|✓|OAS2,OAS3
|Body|✓|OAS2
|FormUnencoded|✓|OAS2
|FormMultipart|✓|OAS2
|Cookie|✗|OAS3
### Schema Support Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Simple|✓|OAS2,OAS3
|Composite|✓|OAS2,OAS3
|Polymorphism|✓|OAS2,OAS3
|Union|✗|OAS3
|allOf|✓|OAS2,OAS3
|anyOf|✓|OAS3
|oneOf|✓|OAS3
|not|✗|OAS3
### Security Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasicAuth|✓|OAS2,OAS3
|ApiKey|✓|OAS2,OAS3
|OpenIDConnect|✗|OAS3
|BearerToken|✓|OAS3
|OAuth2_Implicit|✓|OAS2,OAS3
|OAuth2_Password|✗|OAS2,OAS3
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
### Wire Format Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|JSON|✓|OAS2,OAS3
|XML|✓|OAS2,OAS3
|PROTOBUF|✗|ToolingExtension
|Custom|✓|OAS2,OAS3

View File

@@ -47,6 +47,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>Dict</li>
<li>List</li>
<li>bool</li>
<li>bytes</li>
<li>date</li>

View File

@@ -47,6 +47,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>Dict</li>
<li>List</li>
<li>bool</li>
<li>bytes</li>
<li>date</li>

View File

@@ -637,14 +637,29 @@ public class DefaultCodegen implements CodegenConfig {
}
public void setCircularReferences(Map<String, CodegenModel> models) {
final Map<String, List<CodegenProperty>> dependencyMap = models.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> getModelDependencies(entry.getValue())));
// for allVars
final Map<String, List<CodegenProperty>> allVarsDependencyMap = models.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> getModelDependencies(entry.getValue().getAllVars())));
models.keySet().forEach(name -> setCircularReferencesOnProperties(name, dependencyMap));
models.keySet().forEach(name -> setCircularReferencesOnProperties(name, allVarsDependencyMap));
// for vars
final Map<String, List<CodegenProperty>> varsDependencyMap = models.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> getModelDependencies(entry.getValue().getVars())));
models.keySet().forEach(name -> setCircularReferencesOnProperties(name, varsDependencyMap));
// for oneOf
final Map<String, List<CodegenProperty>> oneOfDependencyMap = models.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> getModelDependencies(
(entry.getValue().getComposedSchemas() != null && entry.getValue().getComposedSchemas().getOneOf() != null)
? entry.getValue().getComposedSchemas().getOneOf() : new ArrayList<CodegenProperty>())));
models.keySet().forEach(name -> setCircularReferencesOnProperties(name, oneOfDependencyMap));
}
private List<CodegenProperty> getModelDependencies(CodegenModel model) {
return model.getAllVars().stream()
private List<CodegenProperty> getModelDependencies( List<CodegenProperty> vars) {
return vars.stream()
.map(prop -> {
if (prop.isContainer) {
return prop.items.dataType == null ? null : prop;

View File

@@ -44,6 +44,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
protected String packageName = "openapi_client";
protected String packageVersion = "1.0.0";
protected String projectName; // for setup.py, e.g. petstore-api
private Map<String, String> schemaKeyToModelNameCache = new HashMap<>();
public AbstractPythonCodegen() {
super();
@@ -68,6 +69,8 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
languageSpecificPrimitives.add("float");
languageSpecificPrimitives.add("list");
languageSpecificPrimitives.add("dict");
languageSpecificPrimitives.add("List");
languageSpecificPrimitives.add("Dict");
languageSpecificPrimitives.add("bool");
languageSpecificPrimitives.add("str");
languageSpecificPrimitives.add("datetime");
@@ -121,19 +124,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
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
@@ -634,6 +625,18 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
@Override
public String toModelName(String name) {
// check if schema-mapping has a different model for this class, so we can use it
// instead of the auto-generated one.
if (schemaMapping.containsKey(name)) {
return schemaMapping.get(name);
}
// memoization
String origName = name;
if (schemaKeyToModelNameCache.containsKey(origName)) {
return schemaKeyToModelNameCache.get(origName);
}
String sanitizedName = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// remove dollar sign
sanitizedName = sanitizedName.replaceAll("$", "");
@@ -659,6 +662,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
if (isReservedWord(camelizedName)) {
String modelName = "Model" + camelizedName; // e.g. return => ModelReturn (after camelize)
LOGGER.warn("{} (reserved word) cannot be used as model name. Renamed to {}", camelizedName, modelName);
schemaKeyToModelNameCache.put(origName, modelName);
return modelName;
}
@@ -666,9 +670,11 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
if (camelizedName.matches("^\\d.*")) {
String modelName = "Model" + camelizedName; // e.g. return => ModelReturn (after camelize)
LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", camelizedName, modelName);
schemaKeyToModelNameCache.put(origName, modelName);
return modelName;
}
schemaKeyToModelNameCache.put(origName, camelizedName);
return camelizedName;
}

View File

@@ -17,10 +17,13 @@
package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -445,4 +448,18 @@ public class PythonLegacyClientCodegen extends AbstractPythonCodegen implements
@Override
public String generatorLanguageVersion() { return "2.7 and 3.4+"; };
@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);
}
}

View File

@@ -98,6 +98,7 @@ org.openapitools.codegen.languages.PhpDataTransferClientCodegen
org.openapitools.codegen.languages.PowerShellClientCodegen
org.openapitools.codegen.languages.ProtobufSchemaCodegen
org.openapitools.codegen.languages.PythonLegacyClientCodegen
org.openapitools.codegen.languages.PythonNextgenClientCodegen
org.openapitools.codegen.languages.PythonClientCodegen
org.openapitools.codegen.languages.PythonFastAPIServerCodegen
org.openapitools.codegen.languages.PythonPriorClientCodegen

View File

@@ -325,8 +325,8 @@ class ApiClient(object):
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('dict('):
sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
if klass.startswith('dict['):
sub_kls = re.match(r'dict\[([^,]*), (.*)\]', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in six.iteritems(data)}

View File

@@ -0,0 +1,55 @@
# {{{projectName}}}
{{#appDescriptionWithNewLines}}
{{{.}}}
{{/appDescriptionWithNewLines}}
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: {{appVersion}}
- Package version: {{packageVersion}}
{{^hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/hideGenerationTimestamp}}
- Build package: {{generatorClass}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
## Requirements.
Python {{{generatorLanguageVersion}}}
## Installation & Usage
### pip install
If the python package is hosted on a repository, you can install directly using:
```sh
pip install git+https://{{gitHost}}/{{{gitUserId}}}/{{{gitRepoId}}}.git
```
(you may need to run `pip` with root permission: `sudo pip install git+https://{{gitHost}}/{{{gitUserId}}}/{{{gitRepoId}}}.git`)
Then import the package:
```python
import {{{packageName}}}
```
### Setuptools
Install via [Setuptools](http://pypi.python.org/pypi/setuptools).
```sh
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)
Then import the package:
```python
import {{{packageName}}}
```
## Getting Started
Please follow the [installation procedure](#installation--usage) and then run the following:
{{> common_README }}

View File

@@ -0,0 +1,44 @@
# {{{projectName}}}
{{#appDescription}}
{{{.}}}
{{/appDescription}}
The `{{packageName}}` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: {{appVersion}}
- Package version: {{packageVersion}}
{{^hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/hideGenerationTimestamp}}
- Build package: {{generatorClass}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
## Requirements.
Python {{{generatorLanguageVersion}}}
## Installation & Usage
This python library package is generated without supporting files like setup.py or requirements files
To be able to use it, you will need these dependencies in your own package that uses this library:
* urllib3 >= 1.25.3
* python-dateutil
{{#asyncio}}
* aiohttp
{{/asyncio}}
{{#tornado}}
* tornado>=4.2,<5
{{/tornado}}
* pydantic
* aenum
## Getting Started
In your own code, to use this library to connect and interact with {{{projectName}}},
you can run the following:
{{> common_README }}

View File

@@ -0,0 +1,7 @@
from __future__ import absolute_import
# flake8: noqa
# import apis into api package
{{#apiInfo}}{{#apis}}from {{apiPackage}}.{{classFilename}} import {{classname}}
{{/apis}}{{/apiInfo}}

View File

@@ -0,0 +1,13 @@
# coding: utf-8
# flake8: noqa
{{>partial_header}}
from __future__ import absolute_import
# import models into model package
{{#models}}
{{#model}}
from {{modelPackage}}.{{classFilename}} import {{classname}}
{{/model}}
{{/models}}

View File

@@ -0,0 +1,32 @@
# coding: utf-8
# flake8: noqa
{{>partial_header}}
from __future__ import absolute_import
__version__ = "{{packageVersion}}"
# import apis into sdk package
{{#apiInfo}}{{#apis}}from {{apiPackage}}.{{classFilename}} import {{classname}}
{{/apis}}{{/apiInfo}}
# import ApiClient
from {{packageName}}.api_client import ApiClient
from {{packageName}}.configuration import Configuration
from {{packageName}}.exceptions import OpenApiException
from {{packageName}}.exceptions import ApiTypeError
from {{packageName}}.exceptions import ApiValueError
from {{packageName}}.exceptions import ApiKeyError
from {{packageName}}.exceptions import ApiAttributeError
from {{packageName}}.exceptions import ApiException
# import models into sdk package
{{#models}}
{{#model}}
from {{modelPackage}}.{{classFilename}} import {{classname}}
{{/model}}
{{/models}}
{{#recursionLimit}}
__import__('sys').setrecursionlimit({{{.}}})
{{/recursionLimit}}

View File

@@ -0,0 +1,264 @@
# coding: utf-8
{{>partial_header}}
from __future__ import absolute_import
import re # noqa: F401
from pydantic import validate_arguments, ValidationError
from typing_extensions import Annotated
{{#imports}}
{{import}}
{{/imports}}
from {{packageName}}.api_client import ApiClient
from {{packageName}}.exceptions import ( # noqa: F401
ApiTypeError,
ApiValueError
)
{{#operations}}
class {{classname}}(object):
"""NOTE: This class is auto generated by OpenAPI Generator
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
def __init__(self, api_client=None):
if api_client is None:
api_client = ApiClient.get_default()
self.api_client = api_client
{{#operation}}
@validate_arguments
def {{operationId}}(self, {{#allParams}}{{paramName}} : {{{vendorExtensions.x-py-typing}}}{{^required}} = None{{/required}}, {{/allParams}}**kwargs) -> {{{returnType}}}{{^returnType}}None{{/returnType}}: # noqa: E501
"""{{{summary}}}{{^summary}}{{operationId}}{{/summary}} # noqa: E501
{{#notes}}
{{{.}}} # noqa: E501
{{/notes}}
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please pass async_req=True
>>> thread = api.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}async_req=True)
>>> result = thread.get()
{{#allParams}}
:param {{paramName}}:{{#description}} {{{.}}}{{/description}}{{#required}} (required){{/required}}{{#optional}}(optional){{/optional}}
:type {{paramName}}: {{dataType}}{{#optional}}, optional{{/optional}}
{{/allParams}}
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:type _preload_content: bool, optional
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: {{returnType}}{{^returnType}}None{{/returnType}}
"""
kwargs['_return_http_data_only'] = True
return self.{{operationId}}_with_http_info({{#allParams}}{{paramName}}, {{/allParams}}**kwargs) # noqa: E501
@validate_arguments
def {{operationId}}_with_http_info(self, {{#allParams}}{{paramName}} : {{{vendorExtensions.x-py-typing}}}{{^required}} = None{{/required}}, {{/allParams}}**kwargs): # noqa: E501
"""{{{summary}}}{{^summary}}{{operationId}}{{/summary}} # noqa: E501
{{#notes}}
{{{.}}} # noqa: E501
{{/notes}}
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please pass async_req=True
>>> thread = api.{{operationId}}_with_http_info({{#allParams}}{{paramName}}, {{/allParams}}async_req=True)
>>> result = thread.get()
{{#allParams}}
:param {{paramName}}:{{#description}} {{{.}}}{{/description}}{{#required}} (required){{/required}}{{#optional}}(optional){{/optional}}
:type {{paramName}}: {{dataType}}{{#optional}}, optional{{/optional}}
{{/allParams}}
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code
and headers
:type _return_http_data_only: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:type _preload_content: bool, optional
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:param _request_auth: set to override the auth_settings for an a single
request; this effectively ignores the authentication
in the spec for a single request.
:type _request_auth: dict, optional
:type _content_type: string, optional: force content-type for the request
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: {{#returnType}}tuple({{.}}, status_code(int), headers(HTTPHeaderDict)){{/returnType}}{{^returnType}}None{{/returnType}}
"""
{{#servers.0}}
_hosts = [
{{#servers}}
'{{{url}}}'{{^-last}},{{/-last}}
{{/servers}}
]
_host = _hosts[0]
if kwargs.get('_host_index'):
_host_index = int(kwargs.get('_host_index'))
if _host_index < 0 or _host_index >= len(_hosts):
raise ApiValueError(
"Invalid host index. Must be 0 <= index < %s"
% len(_host)
)
_host = _hosts[_host_index]
{{/servers.0}}
_params = locals()
_all_params = [
{{#allParams}}
'{{paramName}}'{{^-last}},{{/-last}}
{{/allParams}}
]
_all_params.extend(
[
'async_req',
'_return_http_data_only',
'_preload_content',
'_request_timeout',
'_request_auth',
'_content_type',
'_headers'
]
)
# validate the arguments
for _key, _val in _params['kwargs'].items():
if _key not in _all_params{{#servers.0}} and _key != "_host_index"{{/servers.0}}:
raise ApiTypeError(
"Got an unexpected keyword argument '%s'"
" to method {{operationId}}" % _key
)
_params[_key] = _val
del _params['kwargs']
_collection_formats = {}
# process the path parameters
_path_params = {}
{{#pathParams}}
if _params['{{paramName}}']:
_path_params['{{baseName}}'] = _params['{{paramName}}']
{{#isArray}}
_collection_formats['{{baseName}}'] = '{{collectionFormat}}'
{{/isArray}}
{{/pathParams}}
# process the query parameters
_query_params = []
{{#queryParams}}
if _params.get('{{paramName}}') is not None: # noqa: E501
_query_params.append(('{{baseName}}', _params['{{paramName}}'])){{#isArray}}
_collection_formats['{{baseName}}'] = '{{collectionFormat}}'{{/isArray}}
{{/queryParams}}
# process the header parameters
_header_params = dict(_params.get('_headers', {}))
{{#headerParams}}
if _params['{{paramName}}']:
_header_params['{{baseName}}'] = _params['{{paramName}}']{{#isArray}}
_collection_formats['{{baseName}}'] = '{{collectionFormat}}'{{/isArray}}
{{/headerParams}}
# process the form parameters
_form_params = []
_files = {}
{{#formParams}}
if _params['{{paramName}}']:
{{^isFile}}
_form_params.append(('{{baseName}}', _params['{{paramName}}']))
{{/isFile}}
{{#isFile}}
_files['{{baseName}}'] = _params['{{paramName}}']
{{/isFile}}
{{#isArray}}
_collection_formats['{{baseName}}'] = '{{collectionFormat}}'
{{/isArray}}
{{/formParams}}
# process the body parameter
_body_params = None
{{#bodyParam}}
if _params['{{paramName}}']:
_body_params = _params['{{paramName}}']
{{/bodyParam}}
{{#hasProduces}}
# set the HTTP header `Accept`
_header_params['Accept'] = self.api_client.select_header_accept(
[{{#produces}}'{{{mediaType}}}'{{^-last}}, {{/-last}}{{/produces}}]) # noqa: E501
{{/hasProduces}}
{{#hasConsumes}}
# set the HTTP header `Content-Type`
_content_types_list = _params.get('_content_type',
self.api_client.select_header_content_type(
[{{#consumes}}'{{{mediaType}}}'{{^-last}}, {{/-last}}{{/consumes}}]))
if _content_types_list:
_header_params['Content-Type'] = _content_types_list
{{/hasConsumes}}
# authentication setting
_auth_settings = [{{#authMethods}}'{{name}}'{{^-last}}, {{/-last}}{{/authMethods}}] # noqa: E501
{{#returnType}}
{{#responses}}
{{#-first}}
_response_types_map = {
{{/-first}}
{{^isWildcard}}
'{{code}}': {{#dataType}}"{{.}}"{{/dataType}}{{^dataType}}None{{/dataType}},
{{/isWildcard}}
{{#-last}}
}
{{/-last}}
{{/responses}}
{{/returnType}}
{{^returnType}}
_response_types_map = {}
{{/returnType}}
return self.api_client.call_api(
'{{{path}}}', '{{httpMethod}}',
_path_params,
_query_params,
_header_params,
body=_body_params,
post_params=_form_params,
files=_files,
response_types_map=_response_types_map,
auth_settings=_auth_settings,
async_req=_params.get('async_req'),
_return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501
_preload_content=_params.get('_preload_content', True),
_request_timeout=_params.get('_request_timeout'),
{{#servers.0}}
_host=_host,
{{/servers.0}}
collection_formats=_collection_formats,
_request_auth=_params.get('_request_auth'))
{{/operation}}
{{/operations}}

View File

@@ -0,0 +1,778 @@
# coding: utf-8
{{>partial_header}}
from __future__ import absolute_import
import atexit
import datetime
from dateutil.parser import parse
import json
import mimetypes
from multiprocessing.pool import ThreadPool
import os
import re
import tempfile
from urllib.parse import quote
{{#tornado}}
import tornado.gen
{{/tornado}}
from {{packageName}}.configuration import Configuration
import {{modelPackage}}
from {{packageName}} import rest
from {{packageName}}.exceptions import ApiValueError, ApiException
class ApiClient(object):
"""Generic API client for OpenAPI client library builds.
OpenAPI generic API client. This client handles the client-
server communication, and is invariant across implementations. Specifics of
the methods and models for each application are generated from the OpenAPI
templates.
NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
:param configuration: .Configuration object for this client
:param header_name: a header to pass when making calls to the API.
:param header_value: a header value to pass when making calls to
the API.
:param cookie: a cookie to include in the header when making calls
to the API
:param pool_threads: The number of threads to use for async requests
to the API. More threads means more concurrent API requests.
"""
PRIMITIVE_TYPES = (float, bool, bytes, str, int)
NATIVE_TYPES_MAPPING = {
'int': int,
'long': int, # TODO remove as only py3 is supported?
'float': float,
'str': str,
'bool': bool,
'date': datetime.date,
'datetime': datetime.datetime,
'object': object,
}
_pool = None
def __init__(self, configuration=None, header_name=None, header_value=None,
cookie=None, pool_threads=1):
# use default configuraiton if none is provided
if configuration is None:
configuration = Configuration.get_default()
self.configuration = configuration
self.pool_threads = pool_threads
self.rest_client = rest.RESTClientObject(configuration)
self.default_headers = {}
if header_name is not None:
self.default_headers[header_name] = header_value
self.cookie = cookie
# Set default User-Agent.
self.user_agent = '{{{httpUserAgent}}}{{^httpUserAgent}}OpenAPI-Generator/{{{packageVersion}}}/python{{/httpUserAgent}}'
self.client_side_validation = configuration.client_side_validation
{{#asyncio}}
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_value, traceback):
await self.close()
{{/asyncio}}
{{^asyncio}}
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
{{/asyncio}}
{{#asyncio}}async {{/asyncio}}def close(self):
{{#asyncio}}
await self.rest_client.close()
{{/asyncio}}
if self._pool:
self._pool.close()
self._pool.join()
self._pool = None
if hasattr(atexit, 'unregister'):
atexit.unregister(self.close)
@property
def pool(self):
"""Create thread pool on first request
avoids instantiating unused threadpool for blocking clients.
"""
if self._pool is None:
atexit.register(self.close)
self._pool = ThreadPool(self.pool_threads)
return self._pool
@property
def user_agent(self):
"""User agent for this API client"""
return self.default_headers['User-Agent']
@user_agent.setter
def user_agent(self, value):
self.default_headers['User-Agent'] = value
def set_default_header(self, header_name, header_value):
self.default_headers[header_name] = header_value
_default = None
@classmethod
def get_default(cls):
"""Return new instance of ApiClient.
This method returns newly created, based on default constructor,
object of ApiClient class or returns a copy of default
ApiClient.
:return: The ApiClient object.
"""
if cls._default is None:
cls._default = ApiClient()
return cls._default
@classmethod
def set_default(cls, default):
"""Set default instance of ApiClient.
It stores default ApiClient.
:param default: object of ApiClient.
"""
cls._default = default
{{#tornado}}
@tornado.gen.coroutine
{{/tornado}}
{{#asyncio}}async {{/asyncio}}def __call_api(
self, resource_path, method, path_params=None,
query_params=None, header_params=None, body=None, post_params=None,
files=None, response_types_map=None, auth_settings=None,
_return_http_data_only=None, collection_formats=None,
_preload_content=True, _request_timeout=None, _host=None,
_request_auth=None):
config = self.configuration
# header parameters
header_params = header_params or {}
header_params.update(self.default_headers)
if self.cookie:
header_params['Cookie'] = self.cookie
if header_params:
header_params = self.sanitize_for_serialization(header_params)
header_params = dict(self.parameters_to_tuples(header_params,
collection_formats))
# path parameters
if path_params:
path_params = self.sanitize_for_serialization(path_params)
path_params = self.parameters_to_tuples(path_params,
collection_formats)
for k, v in path_params:
# specified safe chars, encode everything
resource_path = resource_path.replace(
'{%s}' % k,
quote(str(v), safe=config.safe_chars_for_path_param)
)
# post parameters
if post_params or files:
post_params = post_params if post_params else []
post_params = self.sanitize_for_serialization(post_params)
post_params = self.parameters_to_tuples(post_params,
collection_formats)
post_params.extend(self.files_parameters(files))
# auth setting
self.update_params_for_auth(
header_params, query_params, auth_settings,
resource_path, method, body,
request_auth=_request_auth)
# body
if body:
body = self.sanitize_for_serialization(body)
# request url
if _host is None:
url = self.configuration.host + resource_path
else:
# use server/host defined in path or operation instead
url = _host + resource_path
# query parameters
if query_params:
query_params = self.sanitize_for_serialization(query_params)
url_query = self.parameters_to_url_query(query_params,
collection_formats)
url += "?" + url_query
try:
# perform request and return response
response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request(
method, url,
query_params=query_params,
headers=header_params,
post_params=post_params, body=body,
_preload_content=_preload_content,
_request_timeout=_request_timeout)
except ApiException as e:
if e.body:
e.body = e.body.decode('utf-8')
raise e
self.last_response = response_data
return_data = response_data
if not _preload_content:
{{^tornado}}
return return_data
{{/tornado}}
{{#tornado}}
raise tornado.gen.Return(return_data)
{{/tornado}}
response_type = response_types_map.get(str(response_data.status), None)
if response_type not in ["file", "bytes"]:
match = None
content_type = response_data.getheader('content-type')
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data
if response_type:
return_data = self.deserialize(response_data, response_type)
else:
return_data = None
{{^tornado}}
if _return_http_data_only:
return (return_data)
else:
return (return_data, response_data.status,
response_data.getheaders())
{{/tornado}}
{{#tornado}}
if _return_http_data_only:
raise tornado.gen.Return(return_data)
else:
raise tornado.gen.Return((return_data, response_data.status,
response_data.getheaders()))
{{/tornado}}
def sanitize_for_serialization(self, obj):
"""Builds a JSON POST object.
If obj is None, return None.
If obj is str, int, long, float, bool, return directly.
If obj is datetime.datetime, datetime.date
convert to string in iso8601 format.
If obj is list, sanitize each element in the list.
If obj is dict, return the dict.
If obj is OpenAPI model, return the properties dict.
:param obj: The data to serialize.
:return: The serialized form of data.
"""
if obj is None:
return None
elif isinstance(obj, self.PRIMITIVE_TYPES):
return obj
elif isinstance(obj, list):
return [self.sanitize_for_serialization(sub_obj)
for sub_obj in obj]
elif isinstance(obj, tuple):
return tuple(self.sanitize_for_serialization(sub_obj)
for sub_obj in obj)
elif isinstance(obj, (datetime.datetime, datetime.date)):
return obj.isoformat()
if isinstance(obj, dict):
obj_dict = obj
else:
# Convert model obj to dict except
# attributes `openapi_types`, `attribute_map`
# and attributes which value is not None.
# Convert attribute name to json key in
# model definition for request.
obj_dict = obj.to_dict()
return {key: self.sanitize_for_serialization(val)
for key, val in obj_dict.items()}
def deserialize(self, response, response_type):
"""Deserializes response into an object.
:param response: RESTResponse object to be deserialized.
:param response_type: class literal for
deserialized object, or string of class name.
:return: deserialized object.
"""
# handle file downloading
# save response body into a tmp file and return the instance
if response_type == "file":
return self.__deserialize_file(response)
# fetch data from response object
try:
data = json.loads(response.data)
except ValueError:
data = response.data
return self.__deserialize(data, response_type)
def __deserialize(self, data, klass):
"""Deserializes dict, list, str into an object.
:param data: dict, list or str.
:param klass: class literal, or string of class name.
:return: object.
"""
if data is None:
return None
if type(klass) == str:
if klass.startswith('List['):
sub_kls = re.match(r'List\[(.*)]', klass).group(1)
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('Dict['):
sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in data.items()}
# convert str to class
if klass in self.NATIVE_TYPES_MAPPING:
klass = self.NATIVE_TYPES_MAPPING[klass]
else:
klass = getattr({{modelPackage}}, klass)
if klass in self.PRIMITIVE_TYPES:
return self.__deserialize_primitive(data, klass)
elif klass == object:
return self.__deserialize_object(data)
elif klass == datetime.date:
return self.__deserialize_date(data)
elif klass == datetime.datetime:
return self.__deserialize_datetime(data)
else:
return self.__deserialize_model(data, klass)
def call_api(self, resource_path, method,
path_params=None, query_params=None, header_params=None,
body=None, post_params=None, files=None,
response_types_map=None, auth_settings=None,
async_req=None, _return_http_data_only=None,
collection_formats=None,_preload_content=True,
_request_timeout=None, _host=None, _request_auth=None):
"""Makes the HTTP request (synchronous) and returns deserialized data.
To make an async_req request, set the async_req parameter.
:param resource_path: Path to method endpoint.
:param method: Method to call.
:param path_params: Path parameters in the url.
:param query_params: Query parameters in the url.
:param header_params: Header parameters to be
placed in the request header.
:param body: Request body.
:param post_params dict: Request post form parameters,
for `application/x-www-form-urlencoded`, `multipart/form-data`.
:param auth_settings list: Auth Settings names for the request.
:param response: Response data type.
:param files dict: key -> filename, value -> filepath,
for `multipart/form-data`.
:param async_req bool: execute request asynchronously
:param _return_http_data_only: response data without head status code
and headers
:param collection_formats: dict of collection formats for path, query,
header, and post parameters.
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:param _request_auth: set to override the auth_settings for an a single
request; this effectively ignores the authentication
in the spec for a single request.
:type _request_token: dict, optional
:return:
If async_req parameter is True,
the request will be called asynchronously.
The method will return the request thread.
If parameter async_req is False or missing,
then the method will return the response directly.
"""
if not async_req:
return self.__call_api(resource_path, method,
path_params, query_params, header_params,
body, post_params, files,
response_types_map, auth_settings,
_return_http_data_only, collection_formats,
_preload_content, _request_timeout, _host,
_request_auth)
return self.pool.apply_async(self.__call_api, (resource_path,
method, path_params,
query_params,
header_params, body,
post_params, files,
response_types_map,
auth_settings,
_return_http_data_only,
collection_formats,
_preload_content,
_request_timeout,
_host, _request_auth))
def request(self, method, url, query_params=None, headers=None,
post_params=None, body=None, _preload_content=True,
_request_timeout=None):
"""Makes the HTTP request using RESTClient."""
if method == "GET":
return self.rest_client.get_request(url,
query_params=query_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
headers=headers)
elif method == "HEAD":
return self.rest_client.head_request(url,
query_params=query_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
headers=headers)
elif method == "OPTIONS":
return self.rest_client.options_request(url,
query_params=query_params,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout)
elif method == "POST":
return self.rest_client.post_request(url,
query_params=query_params,
headers=headers,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
elif method == "PUT":
return self.rest_client.put_request(url,
query_params=query_params,
headers=headers,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
elif method == "PATCH":
return self.rest_client.patch_request(url,
query_params=query_params,
headers=headers,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
elif method == "DELETE":
return self.rest_client.delete_request(url,
query_params=query_params,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
else:
raise ApiValueError(
"http method must be `GET`, `HEAD`, `OPTIONS`,"
" `POST`, `PATCH`, `PUT` or `DELETE`."
)
def parameters_to_tuples(self, params, collection_formats):
"""Get parameters as list of tuples, formatting collections.
:param params: Parameters as dict or list of two-tuples
:param dict collection_formats: Parameter collection formats
:return: Parameters as list of tuples, collections formatted
"""
new_params = []
if collection_formats is None:
collection_formats = {}
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
if k in collection_formats:
collection_format = collection_formats[k]
if collection_format == 'multi':
new_params.extend((k, value) for value in v)
else:
if collection_format == 'ssv':
delimiter = ' '
elif collection_format == 'tsv':
delimiter = '\t'
elif collection_format == 'pipes':
delimiter = '|'
else: # csv is the default
delimiter = ','
new_params.append(
(k, delimiter.join(str(value) for value in v)))
else:
new_params.append((k, v))
return new_params
def parameters_to_url_query(self, params, collection_formats):
"""Get parameters as list of tuples, formatting collections.
:param params: Parameters as dict or list of two-tuples
:param dict collection_formats: Parameter collection formats
:return: URL query string (e.g. a=Hello%20World&b=123)
"""
new_params = []
if collection_formats is None:
collection_formats = {}
for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
if k in collection_formats:
collection_format = collection_formats[k]
if collection_format == 'multi':
new_params.extend((k, value) for value in v)
else:
if collection_format == 'ssv':
delimiter = ' '
elif collection_format == 'tsv':
delimiter = '\t'
elif collection_format == 'pipes':
delimiter = '|'
else: # csv is the default
delimiter = ','
new_params.append(
(k, delimiter.join(quote(str(value)) for value in v)))
else:
new_params.append((k, v))
return "&".join(["=".join(item) for item in new_params])
def files_parameters(self, files=None):
"""Builds form parameters.
:param files: File parameters.
:return: Form parameters with files.
"""
params = []
if files:
for k, v in files.items():
if not v:
continue
file_names = v if type(v) is list else [v]
for n in file_names:
with open(n, 'rb') as f:
filename = os.path.basename(f.name)
filedata = f.read()
mimetype = (mimetypes.guess_type(filename)[0] or
'application/octet-stream')
params.append(
tuple([k, tuple([filename, filedata, mimetype])]))
return params
def select_header_accept(self, accepts):
"""Returns `Accept` based on an array of accepts provided.
:param accepts: List of headers.
:return: Accept (e.g. application/json).
"""
if not accepts:
return
for accept in accepts:
if re.search('json', accept, re.IGNORECASE):
return accept
return accepts[0]
def select_header_content_type(self, content_types):
"""Returns `Content-Type` based on an array of content_types provided.
:param content_types: List of content-types.
:return: Content-Type (e.g. application/json).
"""
if not content_types:
return None
for content_type in content_types:
if re.search('json', content_type, re.IGNORECASE):
return content_type
return content_types[0]
def update_params_for_auth(self, headers, queries, auth_settings,
resource_path, method, body,
request_auth=None):
"""Updates header and query params based on authentication setting.
:param headers: Header parameters dict to be updated.
:param queries: Query parameters tuple list to be updated.
:param auth_settings: Authentication setting identifiers list.
:resource_path: A string representation of the HTTP request resource path.
:method: A string representation of the HTTP request method.
:body: A object representing the body of the HTTP request.
The object type is the return value of sanitize_for_serialization().
:param request_auth: if set, the provided settings will
override the token in the configuration.
"""
if not auth_settings:
return
if request_auth:
self._apply_auth_params(headers, queries,
resource_path, method, body,
request_auth)
return
for auth in auth_settings:
auth_setting = self.configuration.auth_settings().get(auth)
if auth_setting:
self._apply_auth_params(headers, queries,
resource_path, method, body,
auth_setting)
def _apply_auth_params(self, headers, queries,
resource_path, method, body,
auth_setting):
"""Updates the request parameters based on a single auth_setting
:param headers: Header parameters dict to be updated.
:param queries: Query parameters tuple list to be updated.
:resource_path: A string representation of the HTTP request resource path.
:method: A string representation of the HTTP request method.
:body: A object representing the body of the HTTP request.
The object type is the return value of sanitize_for_serialization().
:param auth_setting: auth settings for the endpoint
"""
if auth_setting['in'] == 'cookie':
headers['Cookie'] = auth_setting['value']
elif auth_setting['in'] == 'header':
if auth_setting['type'] != 'http-signature':
headers[auth_setting['key']] = auth_setting['value']
{{#hasHttpSignatureMethods}}
else:
# The HTTP signature scheme requires multiple HTTP headers
# that are calculated dynamically.
signing_info = self.configuration.signing_info
auth_headers = signing_info.get_http_signature_headers(
resource_path, method, headers, body, queries)
headers.update(auth_headers)
{{/hasHttpSignatureMethods}}
elif auth_setting['in'] == 'query':
queries.append((auth_setting['key'], auth_setting['value']))
else:
raise ApiValueError(
'Authentication token must be in `query` or `header`'
)
def __deserialize_file(self, response):
"""Deserializes body to file
Saves response body into a file in a temporary folder,
using the filename from the `Content-Disposition` header if provided.
:param response: RESTResponse.
:return: file path.
"""
fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path)
os.close(fd)
os.remove(path)
content_disposition = response.getheader("Content-Disposition")
if content_disposition:
filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?',
content_disposition).group(1)
path = os.path.join(os.path.dirname(path), filename)
with open(path, "wb") as f:
f.write(response.data)
return path
def __deserialize_primitive(self, data, klass):
"""Deserializes string to primitive type.
:param data: str.
:param klass: class literal.
:return: int, long, float, str, bool.
"""
try:
return klass(data)
except UnicodeEncodeError:
return str(data)
except TypeError:
return data
def __deserialize_object(self, value):
"""Return an original value.
:return: object.
"""
return value
def __deserialize_date(self, string):
"""Deserializes string to date.
:param string: str.
:return: date.
"""
try:
return parse(string).date()
except ImportError:
return string
except ValueError:
raise rest.ApiException(
status=0,
reason="Failed to parse `{0}` as date object".format(string)
)
def __deserialize_datetime(self, string):
"""Deserializes string to datetime.
The string should be in iso8601 datetime format.
:param string: str.
:return: datetime.
"""
try:
return parse(string)
except ImportError:
return string
except ValueError:
raise rest.ApiException(
status=0,
reason=(
"Failed to parse `{0}` as datetime object"
.format(string)
)
)
def __deserialize_model(self, data, klass):
"""Deserializes list or dict to model.
:param data: dict, list.
:param klass: class literal.
:return: model object.
"""
return klass.from_dict(data)

View File

@@ -0,0 +1,76 @@
# {{packageName}}.{{classname}}{{#description}}
{{.}}{{/description}}
All URIs are relative to *{{basePath}}*
Method | HTTP request | Description
------------- | ------------- | -------------
{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{summary}}
{{/operation}}{{/operations}}
{{#operations}}
{{#operation}}
# **{{{operationId}}}**
> {{#returnType}}{{{.}}} {{/returnType}}{{{operationId}}}({{#allParams}}{{#required}}{{{paramName}}}{{/required}}{{^required}}{{{paramName}}}={{{paramName}}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{{summary}}}{{#notes}}
{{{.}}}{{/notes}}
### Example
{{#hasAuthMethods}}
{{#authMethods}}
{{#isBasic}}
{{#isBasicBasic}}
* Basic Authentication ({{name}}):
{{/isBasicBasic}}
{{#isBasicBearer}}
* Bearer{{#bearerFormat}} ({{{.}}}){{/bearerFormat}} Authentication ({{name}}):
{{/isBasicBearer}}
{{/isBasic}}
{{#isApiKey}}
* Api Key Authentication ({{name}}):
{{/isApiKey }}
{{#isOAuth}}
* OAuth Authentication ({{name}}):
{{/isOAuth }}
{{> api_doc_example }}
{{/authMethods}}
{{/hasAuthMethods}}
{{^hasAuthMethods}}
{{> api_doc_example }}
{{/hasAuthMethods}}
### Parameters
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
{{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{baseType}}.md){{/isPrimitiveType}}{{/isFile}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{.}}]{{/defaultValue}}
{{/allParams}}
### Return type
{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}}
### Authorization
{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}}
### HTTP request headers
- **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
- **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}}
{{#responses.0}}
### HTTP response details
| Status code | Description | Response headers |
|-------------|-------------|------------------|
{{#responses}}
**{{code}}** | {{message}} | {{#headers}} * {{baseName}} - {{description}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} |
{{/responses}}
{{/responses.0}}
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
{{/operation}}
{{/operations}}

View File

@@ -0,0 +1,33 @@
```python
from __future__ import print_function
import time
import os
import {{{packageName}}}
from {{{packageName}}}.rest import ApiException
from pprint import pprint
{{> python_doc_auth_partial}}
# Enter a context with an instance of the API client
{{#hasAuthMethods}}
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient(configuration) as api_client:
{{/hasAuthMethods}}
{{^hasAuthMethods}}
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient() as api_client:
{{/hasAuthMethods}}
# Create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}(api_client)
{{#allParams}}
{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
{{/allParams}}
try:
{{#summary}}
# {{{.}}}
{{/summary}}
{{#returnType}}api_response = {{/returnType}}{{#asyncio}}await {{/asyncio}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}
print("The response of {{classname}}->{{operationId}}:\n")
pprint(api_response)
{{/returnType}}
except Exception as e:
print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e)
```

View File

@@ -0,0 +1,37 @@
# coding: utf-8
{{>partial_header}}
from __future__ import absolute_import
import unittest
import {{packageName}}
from {{apiPackage}}.{{classFilename}} import {{classname}} # noqa: E501
from {{packageName}}.rest import ApiException
class {{#operations}}Test{{classname}}(unittest.TestCase):
"""{{classname}} unit test stubs"""
def setUp(self):
self.api = {{apiPackage}}.{{classFilename}}.{{classname}}() # noqa: E501
def tearDown(self):
pass
{{#operation}}
def test_{{operationId}}(self):
"""Test case for {{{operationId}}}
{{#summary}}
{{{.}}} # noqa: E501
{{/summary}}
"""
pass
{{/operation}}
{{/operations}}
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,241 @@
# coding: utf-8
{{>partial_header}}
import io
import json
import logging
import re
import ssl
import aiohttp
from urllib.parse import urlencode, quote_plus
from {{packageName}}.exceptions import ApiException, ApiValueError
logger = logging.getLogger(__name__)
class RESTResponse(io.IOBase):
def __init__(self, resp, data):
self.aiohttp_response = resp
self.status = resp.status
self.reason = resp.reason
self.data = data
def getheaders(self):
"""Returns a CIMultiDictProxy of the response headers."""
return self.aiohttp_response.headers
def getheader(self, name, default=None):
"""Returns a given response header."""
return self.aiohttp_response.headers.get(name, default)
class RESTClientObject(object):
def __init__(self, configuration, pools_size=4, maxsize=None):
# maxsize is number of requests to host that are allowed in parallel
if maxsize is None:
maxsize = configuration.connection_pool_maxsize
ssl_context = ssl.create_default_context(cafile=configuration.ssl_ca_cert)
if configuration.cert_file:
ssl_context.load_cert_chain(
configuration.cert_file, keyfile=configuration.key_file
)
if not configuration.verify_ssl:
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
connector = aiohttp.TCPConnector(
limit=maxsize,
ssl=ssl_context
)
self.proxy = configuration.proxy
self.proxy_headers = configuration.proxy_headers
# https pool manager
self.pool_manager = aiohttp.ClientSession(
connector=connector,
trust_env=True
)
async def close(self):
await self.pool_manager.close()
async def request(self, method, url, query_params=None, headers=None,
body=None, post_params=None, _preload_content=True,
_request_timeout=None):
"""Execute request
:param method: http request method
:param url: http request url
:param query_params: query parameters in the url
:param headers: http request headers
:param body: request json body, for `application/json`
:param post_params: request post parameters,
`application/x-www-form-urlencoded`
and `multipart/form-data`
:param _preload_content: this is a non-applicable field for
the AiohttpClient.
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
"""
method = method.upper()
assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',
'PATCH', 'OPTIONS']
if post_params and body:
raise ApiValueError(
"body parameter cannot be used with post_params parameter."
)
post_params = post_params or {}
headers = headers or {}
# url already contains the URL query string
# so reset query_params to empty dict
query_params = {}
timeout = _request_timeout or 5 * 60
if 'Content-Type' not in headers:
headers['Content-Type'] = 'application/json'
args = {
"method": method,
"url": url,
"timeout": timeout,
"headers": headers
}
if self.proxy:
args["proxy"] = self.proxy
if self.proxy_headers:
args["proxy_headers"] = self.proxy_headers
if query_params:
args["url"] += '?' + urlencode(query_params)
# For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
if re.search('json', headers['Content-Type'], re.IGNORECASE):
if body is not None:
body = json.dumps(body)
args["data"] = body
elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501
args["data"] = aiohttp.FormData(post_params)
elif headers['Content-Type'] == 'multipart/form-data':
# must del headers['Content-Type'], or the correct
# Content-Type which generated by aiohttp
del headers['Content-Type']
data = aiohttp.FormData()
for param in post_params:
k, v = param
if isinstance(v, tuple) and len(v) == 3:
data.add_field(k,
value=v[1],
filename=v[0],
content_type=v[2])
else:
data.add_field(k, v)
args["data"] = data
# Pass a `bytes` parameter directly in the body to support
# other content types than Json when `body` argument is provided
# in serialized form
elif isinstance(body, bytes):
args["data"] = body
else:
# Cannot generate the request from given parameters
msg = """Cannot prepare a request message for provided
arguments. Please check that your arguments match
declared content type."""
raise ApiException(status=0, reason=msg)
r = await self.pool_manager.request(**args)
if _preload_content:
data = await r.read()
r = RESTResponse(r, data)
# log response body
logger.debug("response body: %s", r.data)
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
return r
async def get_request(self, url, headers=None, query_params=None,
_preload_content=True, _request_timeout=None):
return (await self.request("GET", url,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
query_params=query_params))
async def head_request(self, url, headers=None, query_params=None,
_preload_content=True, _request_timeout=None):
return (await self.request("HEAD", url,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
query_params=query_params))
async def options_request(self, url, headers=None, query_params=None,
post_params=None, body=None, _preload_content=True,
_request_timeout=None):
return (await self.request("OPTIONS", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body))
async def delete_request(self, url, headers=None, query_params=None, body=None,
_preload_content=True, _request_timeout=None):
return (await self.request("DELETE", url,
headers=headers,
query_params=query_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body))
async def post_request(self, url, headers=None, query_params=None,
post_params=None, body=None, _preload_content=True,
_request_timeout=None):
return (await self.request("POST", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body))
async def put_request(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
return (await self.request("PUT", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body))
async def patch_request(self, url, headers=None, query_params=None,
post_params=None, body=None, _preload_content=True,
_request_timeout=None):
return (await self.request("PATCH", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body))

View File

@@ -0,0 +1,83 @@
```python
from __future__ import print_function
{{#apiInfo}}{{#apis}}{{#-last}}{{#hasHttpSignatureMethods}}import datetime{{/hasHttpSignatureMethods}}{{/-last}}{{/apis}}{{/apiInfo}}
import time
import {{{packageName}}}
from {{{packageName}}}.rest import ApiException
from pprint import pprint
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}
{{> python_doc_auth_partial}}
# Enter a context with an instance of the API client
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}(api_client)
{{#allParams}}
{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
{{/allParams}}
try:
{{#summary}}
# {{{.}}}
{{/summary}}
{{#returnType}}api_response = {{/returnType}}{{#asyncio}}await {{/asyncio}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}
print("The response of {{classname}}->{{operationId}}:\n")
pprint(api_response)
{{/returnType}}
except ApiException as e:
print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e)
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
```
## Documentation for API Endpoints
All URIs are relative to *{{{basePath}}}*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{summary}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
## Documentation For Models
{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
{{/model}}{{/models}}
## Documentation For Authorization
{{^authMethods}}
All endpoints do not require authorization.
{{/authMethods}}
{{#authMethods}}
{{#last}} Authentication schemes defined for the API:{{/last}}
## {{{name}}}
{{#isApiKey}}
- **Type**: API key
- **API key parameter name**: {{{keyParamName}}}
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasic}}
{{#isBasicBasic}}
- **Type**: HTTP basic authentication
{{/isBasicBasic}}
{{#isBasicBearer}}
- **Type**: Bearer authentication{{#bearerFormat}} ({{{.}}}){{/bearerFormat}}
{{/isBasicBearer}}
{{/isBasic}}
{{#isOAuth}}
- **Type**: OAuth
- **Flow**: {{{flow}}}
- **Authorization URL**: {{{authorizationUrl}}}
- **Scopes**: {{^scopes}}N/A{{/scopes}}
{{#scopes}} - **{{{scope}}}**: {{{description}}}
{{/scopes}}
{{/isOAuth}}
{{/authMethods}}
## Author
{{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}}
{{/-last}}{{/apis}}{{/apiInfo}}

View File

@@ -0,0 +1,651 @@
# coding: utf-8
{{>partial_header}}
from __future__ import absolute_import
import copy
import logging
{{^asyncio}}
import multiprocessing
{{/asyncio}}
import sys
import urllib3
import http.client as httplib
from {{packageName}}.exceptions import ApiValueError
JSON_SCHEMA_VALIDATION_KEYWORDS = {
'multipleOf', 'maximum', 'exclusiveMaximum',
'minimum', 'exclusiveMinimum', 'maxLength',
'minLength', 'pattern', 'maxItems', 'minItems'
}
class Configuration(object):
"""NOTE: This class is auto generated by OpenAPI Generator
Ref: https://openapi-generator.tech
Do not edit the class manually.
:param host: Base url.
:param api_key: Dict to store API key(s).
Each entry in the dict specifies an API key.
The dict key is the name of the security scheme in the OAS specification.
The dict value is the API key secret.
:param api_key_prefix: Dict to store API prefix (e.g. Bearer).
The dict key is the name of the security scheme in the OAS specification.
The dict value is an API key prefix when generating the auth data.
:param username: Username for HTTP basic authentication.
:param password: Password for HTTP basic authentication.
:param discard_unknown_keys: Boolean value indicating whether to discard
unknown properties. A server may send a response that includes additional
properties that are not known by the client in the following scenarios:
1. The OpenAPI document is incomplete, i.e. it does not match the server
implementation.
2. The client was generated using an older version of the OpenAPI document
and the server has been upgraded since then.
If a schema in the OpenAPI document defines the additionalProperties attribute,
then all undeclared properties received by the server are injected into the
additional properties map. In that case, there are undeclared properties, and
nothing to discard.
:param disabled_client_side_validations (string): Comma-separated list of
JSON schema validation keywords to disable JSON schema structural validation
rules. The following keywords may be specified: multipleOf, maximum,
exclusiveMaximum, minimum, exclusiveMinimum, maxLength, minLength, pattern,
maxItems, minItems.
By default, the validation is performed for data generated locally by the client
and data received from the server, independent of any validation performed by
the server side. If the input data does not satisfy the JSON schema validation
rules specified in the OpenAPI document, an exception is raised.
If disabled_client_side_validations is set, structural validation is
disabled. This can be useful to troubleshoot data validation problem, such as
when the OpenAPI document validation rules do not match the actual API data
received by the server.
{{#hasHttpSignatureMethods}}
:param signing_info: Configuration parameters for the HTTP signature security scheme.
Must be an instance of {{{packageName}}}.signing.HttpSigningConfiguration
{{/hasHttpSignatureMethods}}
:param server_index: Index to servers configuration.
:param server_variables: Mapping with string values to replace variables in
templated server configuration. The validation of enums is performed for
variables with defined enum values before.
:param server_operation_index: Mapping from operation ID to an index to server
configuration.
:param server_operation_variables: Mapping from operation ID to a mapping with
string values to replace variables in templated server configuration.
The validation of enums is performed for variables with defined enum values before.
:param ssl_ca_cert: str - the path to a file of concatenated CA certificates
in PEM format.
{{#hasAuthMethods}}
:Example:
{{#hasApiKeyMethods}}
API Key Authentication Example.
Given the following security scheme in the OpenAPI specification:
components:
securitySchemes:
cookieAuth: # name for the security scheme
type: apiKey
in: cookie
name: JSESSIONID # cookie name
You can programmatically set the cookie:
conf = {{{packageName}}}.Configuration(
api_key={'cookieAuth': 'abc123'}
api_key_prefix={'cookieAuth': 'JSESSIONID'}
)
The following cookie will be added to the HTTP request:
Cookie: JSESSIONID abc123
{{/hasApiKeyMethods}}
{{#hasHttpBasicMethods}}
HTTP Basic Authentication Example.
Given the following security scheme in the OpenAPI specification:
components:
securitySchemes:
http_basic_auth:
type: http
scheme: basic
Configure API client with HTTP basic authentication:
conf = {{{packageName}}}.Configuration(
username='the-user',
password='the-password',
)
{{/hasHttpBasicMethods}}
{{#hasHttpSignatureMethods}}
HTTP Signature Authentication Example.
Given the following security scheme in the OpenAPI specification:
components:
securitySchemes:
http_basic_auth:
type: http
scheme: signature
Configure API client with HTTP signature authentication. Use the 'hs2019' signature scheme,
sign the HTTP requests with the RSA-SSA-PSS signature algorithm, and set the expiration time
of the signature to 5 minutes after the signature has been created.
Note you can use the constants defined in the {{{packageName}}}.signing module, and you can
also specify arbitrary HTTP headers to be included in the HTTP signature, except for the
'Authorization' header, which is used to carry the signature.
One may be tempted to sign all headers by default, but in practice it rarely works.
This is because explicit proxies, transparent proxies, TLS termination endpoints or
load balancers may add/modify/remove headers. Include the HTTP headers that you know
are not going to be modified in transit.
conf = {{{packageName}}}.Configuration(
signing_info = {{{packageName}}}.signing.HttpSigningConfiguration(
key_id = 'my-key-id',
private_key_path = 'rsa.pem',
signing_scheme = {{{packageName}}}.signing.SCHEME_HS2019,
signing_algorithm = {{{packageName}}}.signing.ALGORITHM_RSASSA_PSS,
signed_headers = [{{{packageName}}}.signing.HEADER_REQUEST_TARGET,
{{{packageName}}}.signing.HEADER_CREATED,
{{{packageName}}}.signing.HEADER_EXPIRES,
{{{packageName}}}.signing.HEADER_HOST,
{{{packageName}}}.signing.HEADER_DATE,
{{{packageName}}}.signing.HEADER_DIGEST,
'Content-Type',
'User-Agent'
],
signature_max_validity = datetime.timedelta(minutes=5)
)
)
{{/hasHttpSignatureMethods}}
{{/hasAuthMethods}}
"""
_default = None
def __init__(self, host=None,
api_key=None, api_key_prefix=None,
username=None, password=None,
discard_unknown_keys=False,
disabled_client_side_validations="",
{{#hasHttpSignatureMethods}}
signing_info=None,
{{/hasHttpSignatureMethods}}
server_index=None, server_variables=None,
server_operation_index=None, server_operation_variables=None,
ssl_ca_cert=None,
):
"""Constructor
"""
self._base_path = "{{{basePath}}}" if host is None else host
"""Default Base url
"""
self.server_index = 0 if server_index is None and host is None else server_index
self.server_operation_index = server_operation_index or {}
"""Default server index
"""
self.server_variables = server_variables or {}
self.server_operation_variables = server_operation_variables or {}
"""Default server variables
"""
self.temp_folder_path = None
"""Temp file folder for downloading files
"""
# Authentication Settings
self.api_key = {}
if api_key:
self.api_key = api_key
"""dict to store API key(s)
"""
self.api_key_prefix = {}
if api_key_prefix:
self.api_key_prefix = api_key_prefix
"""dict to store API prefix (e.g. Bearer)
"""
self.refresh_api_key_hook = None
"""function hook to refresh API key if expired
"""
self.username = username
"""Username for HTTP basic authentication
"""
self.password = password
"""Password for HTTP basic authentication
"""
self.discard_unknown_keys = discard_unknown_keys
self.disabled_client_side_validations = disabled_client_side_validations
{{#hasHttpSignatureMethods}}
if signing_info is not None:
signing_info.host = host
self.signing_info = signing_info
"""The HTTP signing configuration
"""
{{/hasHttpSignatureMethods}}
{{#hasOAuthMethods}}
self.access_token = None
"""access token for OAuth/Bearer
"""
{{/hasOAuthMethods}}
{{^hasOAuthMethods}}
{{#hasBearerMethods}}
self.access_token = None
"""access token for OAuth/Bearer
"""
{{/hasBearerMethods}}
{{/hasOAuthMethods}}
self.logger = {}
"""Logging Settings
"""
self.logger["package_logger"] = logging.getLogger("{{packageName}}")
self.logger["urllib3_logger"] = logging.getLogger("urllib3")
self.logger_format = '%(asctime)s %(levelname)s %(message)s'
"""Log format
"""
self.logger_stream_handler = None
"""Log stream handler
"""
self.logger_file_handler = None
"""Log file handler
"""
self.logger_file = None
"""Debug file location
"""
self.debug = False
"""Debug switch
"""
self.verify_ssl = True
"""SSL/TLS verification
Set this to false to skip verifying SSL certificate when calling API
from https server.
"""
self.ssl_ca_cert = ssl_ca_cert
"""Set this to customize the certificate file to verify the peer.
"""
self.cert_file = None
"""client certificate file
"""
self.key_file = None
"""client key file
"""
self.assert_hostname = None
"""Set this to True/False to enable/disable SSL hostname verification.
"""
{{#asyncio}}
self.connection_pool_maxsize = 100
"""This value is passed to the aiohttp to limit simultaneous connections.
Default values is 100, None means no-limit.
"""
{{/asyncio}}
{{^asyncio}}
self.connection_pool_maxsize = multiprocessing.cpu_count() * 5
"""urllib3 connection pool's maximum number of connections saved
per pool. urllib3 uses 1 connection as default value, but this is
not the best value when you are making a lot of possibly parallel
requests to the same host, which is often the case here.
cpu_count * 5 is used as default value to increase performance.
"""
{{/asyncio}}
self.proxy = None
"""Proxy URL
"""
self.proxy_headers = None
"""Proxy headers
"""
self.safe_chars_for_path_param = ''
"""Safe chars for path_param
"""
self.retries = None
"""Adding retries to override urllib3 default value 3
"""
# Enable client side validation
self.client_side_validation = True
self.socket_options = None
"""Options to pass down to the underlying urllib3 socket
"""
def __deepcopy__(self, memo):
cls = self.__class__
result = cls.__new__(cls)
memo[id(self)] = result
for k, v in self.__dict__.items():
if k not in ('logger', 'logger_file_handler'):
setattr(result, k, copy.deepcopy(v, memo))
# shallow copy of loggers
result.logger = copy.copy(self.logger)
# use setters to configure loggers
result.logger_file = self.logger_file
result.debug = self.debug
return result
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
if name == 'disabled_client_side_validations':
s = set(filter(None, value.split(',')))
for v in s:
if v not in JSON_SCHEMA_VALIDATION_KEYWORDS:
raise ApiValueError(
"Invalid keyword: '{0}''".format(v))
self._disabled_client_side_validations = s
{{#hasHttpSignatureMethods}}
if name == "signing_info" and value is not None:
# Ensure the host parameter from signing info is the same as
# Configuration.host.
value.host = self.host
{{/hasHttpSignatureMethods}}
@classmethod
def set_default(cls, default):
"""Set default instance of configuration.
It stores default configuration, which can be
returned by get_default_copy method.
:param default: object of Configuration
"""
cls._default = default
@classmethod
def get_default_copy(cls):
"""Deprecated. Please use `get_default` instead.
Deprecated. Please use `get_default` instead.
:return: The configuration object.
"""
return cls.get_default()
@classmethod
def get_default(cls):
"""Return the default configuration.
This method returns newly created, based on default constructor,
object of Configuration class or returns a copy of default
configuration.
:return: The configuration object.
"""
if cls._default is None:
cls._default = Configuration()
return cls._default
@property
def logger_file(self):
"""The logger file.
If the logger_file is None, then add stream handler and remove file
handler. Otherwise, add file handler and remove stream handler.
:param value: The logger_file path.
:type: str
"""
return self.__logger_file
@logger_file.setter
def logger_file(self, value):
"""The logger file.
If the logger_file is None, then add stream handler and remove file
handler. Otherwise, add file handler and remove stream handler.
:param value: The logger_file path.
:type: str
"""
self.__logger_file = value
if self.__logger_file:
# If set logging file,
# then add file handler and remove stream handler.
self.logger_file_handler = logging.FileHandler(self.__logger_file)
self.logger_file_handler.setFormatter(self.logger_formatter)
for _, logger in self.logger.items():
logger.addHandler(self.logger_file_handler)
@property
def debug(self):
"""Debug status
:param value: The debug status, True or False.
:type: bool
"""
return self.__debug
@debug.setter
def debug(self, value):
"""Debug status
:param value: The debug status, True or False.
:type: bool
"""
self.__debug = value
if self.__debug:
# if debug status is True, turn on debug logging
for _, logger in self.logger.items():
logger.setLevel(logging.DEBUG)
# turn on httplib debug
httplib.HTTPConnection.debuglevel = 1
else:
# if debug status is False, turn off debug logging,
# setting log level to default `logging.WARNING`
for _, logger in self.logger.items():
logger.setLevel(logging.WARNING)
# turn off httplib debug
httplib.HTTPConnection.debuglevel = 0
@property
def logger_format(self):
"""The logger format.
The logger_formatter will be updated when sets logger_format.
:param value: The format string.
:type: str
"""
return self.__logger_format
@logger_format.setter
def logger_format(self, value):
"""The logger format.
The logger_formatter will be updated when sets logger_format.
:param value: The format string.
:type: str
"""
self.__logger_format = value
self.logger_formatter = logging.Formatter(self.__logger_format)
def get_api_key_with_prefix(self, identifier, alias=None):
"""Gets API key (with prefix if set).
:param identifier: The identifier of apiKey.
:param alias: The alternative identifier of apiKey.
:return: The token for api key authentication.
"""
if self.refresh_api_key_hook is not None:
self.refresh_api_key_hook(self)
key = self.api_key.get(identifier, self.api_key.get(alias) if alias is not None else None)
if key:
prefix = self.api_key_prefix.get(identifier)
if prefix:
return "%s %s" % (prefix, key)
else:
return key
def get_basic_auth_token(self):
"""Gets HTTP basic authentication header (string).
:return: The token for basic HTTP authentication.
"""
username = ""
if self.username is not None:
username = self.username
password = ""
if self.password is not None:
password = self.password
return urllib3.util.make_headers(
basic_auth=username + ':' + password
).get('authorization')
def auth_settings(self):
"""Gets Auth Settings dict for api client.
:return: The Auth Settings information dict.
"""
auth = {}
{{#authMethods}}
{{#isApiKey}}
if '{{name}}' in self.api_key{{#vendorExtensions.x-auth-id-alias}} or '{{.}}' in self.api_key{{/vendorExtensions.x-auth-id-alias}}:
auth['{{name}}'] = {
'type': 'api_key',
'in': {{#isKeyInCookie}}'cookie'{{/isKeyInCookie}}{{#isKeyInHeader}}'header'{{/isKeyInHeader}}{{#isKeyInQuery}}'query'{{/isKeyInQuery}},
'key': '{{keyParamName}}',
'value': self.get_api_key_with_prefix(
'{{name}}',{{#vendorExtensions.x-auth-id-alias}}
alias='{{.}}',{{/vendorExtensions.x-auth-id-alias}}
),
}
{{/isApiKey}}
{{#isBasic}}
{{#isBasicBasic}}
if self.username is not None and self.password is not None:
auth['{{name}}'] = {
'type': 'basic',
'in': 'header',
'key': 'Authorization',
'value': self.get_basic_auth_token()
}
{{/isBasicBasic}}
{{#isBasicBearer}}
if self.access_token is not None:
auth['{{name}}'] = {
'type': 'bearer',
'in': 'header',
{{#bearerFormat}}
'format': '{{{.}}}',
{{/bearerFormat}}
'key': 'Authorization',
'value': 'Bearer ' + self.access_token
}
{{/isBasicBearer}}
{{#isHttpSignature}}
if self.signing_info is not None:
auth['{{name}}'] = {
'type': 'http-signature',
'in': 'header',
'key': 'Authorization',
'value': None # Signature headers are calculated for every HTTP request
}
{{/isHttpSignature}}
{{/isBasic}}
{{#isOAuth}}
if self.access_token is not None:
auth['{{name}}'] = {
'type': 'oauth2',
'in': 'header',
'key': 'Authorization',
'value': 'Bearer ' + self.access_token
}
{{/isOAuth}}
{{/authMethods}}
return auth
def to_debug_report(self):
"""Gets the essential information for debugging.
:return: The report for debugging.
"""
return "Python SDK Debug Report:\n"\
"OS: {env}\n"\
"Python Version: {pyversion}\n"\
"Version of the API: {{version}}\n"\
"SDK Package Version: {{packageVersion}}".\
format(env=sys.platform, pyversion=sys.version)
def get_host_settings(self):
"""Gets an array of host settings
:return: An array of host settings
"""
return [
{{#servers}}
{
'url': "{{{url}}}",
'description': "{{{description}}}{{^description}}No description provided{{/description}}",
{{#variables}}
{{#-first}}
'variables': {
{{/-first}}
'{{{name}}}': {
'description': "{{{description}}}{{^description}}No description provided{{/description}}",
'default_value': "{{{defaultValue}}}",
{{#enumValues}}
{{#-first}}
'enum_values': [
{{/-first}}
"{{{.}}}"{{^-last}},{{/-last}}
{{#-last}}
]
{{/-last}}
{{/enumValues}}
}{{^-last}},{{/-last}}
{{#-last}}
}
{{/-last}}
{{/variables}}
}{{^-last}},{{/-last}}
{{/servers}}
]
def get_host_from_settings(self, index, variables=None, servers=None):
"""Gets host URL based on the index and variables
:param index: array index of the host settings
:param variables: hash of variable and the corresponding value
:param servers: an array of host settings or None
:return: URL based on host settings
"""
if index is None:
return self._base_path
variables = {} if variables is None else variables
servers = self.get_host_settings() if servers is None else servers
try:
server = servers[index]
except IndexError:
raise ValueError(
"Invalid index {0} when selecting the host settings. "
"Must be less than {1}".format(index, len(servers)))
url = server['url']
# go through variables and replace placeholders
for variable_name, variable in server.get('variables', {}).items():
used_value = variables.get(
variable_name, variable['default_value'])
if 'enum_values' in variable \
and used_value not in variable['enum_values']:
raise ValueError(
"The variable `{0}` in the host URL has invalid value "
"{1}. Must be {2}.".format(
variable_name, variables[variable_name],
variable['enum_values']))
url = url.replace("{" + variable_name + "}", used_value)
return url
@property
def host(self):
"""Return generated host."""
return self.get_host_from_settings(self.server_index, variables=self.server_variables)
@host.setter
def host(self, value):
"""Fix base path."""
self._base_path = value
self.server_index = None

View File

@@ -0,0 +1,152 @@
# coding: utf-8
{{>partial_header}}
class OpenApiException(Exception):
"""The base exception class for all OpenAPIExceptions"""
class ApiTypeError(OpenApiException, TypeError):
def __init__(self, msg, path_to_item=None, valid_classes=None,
key_type=None):
""" Raises an exception for TypeErrors
Args:
msg (str): the exception message
Keyword Args:
path_to_item (list): a list of keys an indices to get to the
current_item
None if unset
valid_classes (tuple): the primitive classes that current item
should be an instance of
None if unset
key_type (bool): False if our value is a value in a dict
True if it is a key in a dict
False if our item is an item in a list
None if unset
"""
self.path_to_item = path_to_item
self.valid_classes = valid_classes
self.key_type = key_type
full_msg = msg
if path_to_item:
full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
super(ApiTypeError, self).__init__(full_msg)
class ApiValueError(OpenApiException, ValueError):
def __init__(self, msg, path_to_item=None):
"""
Args:
msg (str): the exception message
Keyword Args:
path_to_item (list) the path to the exception in the
received_data dict. None if unset
"""
self.path_to_item = path_to_item
full_msg = msg
if path_to_item:
full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
super(ApiValueError, self).__init__(full_msg)
class ApiAttributeError(OpenApiException, AttributeError):
def __init__(self, msg, path_to_item=None):
"""
Raised when an attribute reference or assignment fails.
Args:
msg (str): the exception message
Keyword Args:
path_to_item (None/list) the path to the exception in the
received_data dict
"""
self.path_to_item = path_to_item
full_msg = msg
if path_to_item:
full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
super(ApiAttributeError, self).__init__(full_msg)
class ApiKeyError(OpenApiException, KeyError):
def __init__(self, msg, path_to_item=None):
"""
Args:
msg (str): the exception message
Keyword Args:
path_to_item (None/list) the path to the exception in the
received_data dict
"""
self.path_to_item = path_to_item
full_msg = msg
if path_to_item:
full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
super(ApiKeyError, self).__init__(full_msg)
class ApiException(OpenApiException):
def __init__(self, status=None, reason=None, http_resp=None):
if http_resp:
self.status = http_resp.status
self.reason = http_resp.reason
self.body = http_resp.data
self.headers = http_resp.getheaders()
else:
self.status = status
self.reason = reason
self.body = None
self.headers = None
def __str__(self):
"""Custom error messages for exception"""
error_message = "({0})\n"\
"Reason: {1}\n".format(self.status, self.reason)
if self.headers:
error_message += "HTTP response headers: {0}\n".format(
self.headers)
if self.body:
error_message += "HTTP response body: {0}\n".format(self.body)
return error_message
class NotFoundException(ApiException):
def __init__(self, status=None, reason=None, http_resp=None):
super(NotFoundException, self).__init__(status, reason, http_resp)
class UnauthorizedException(ApiException):
def __init__(self, status=None, reason=None, http_resp=None):
super(UnauthorizedException, self).__init__(status, reason, http_resp)
class ForbiddenException(ApiException):
def __init__(self, status=None, reason=None, http_resp=None):
super(ForbiddenException, self).__init__(status, reason, http_resp)
class ServiceException(ApiException):
def __init__(self, status=None, reason=None, http_resp=None):
super(ServiceException, self).__init__(status, reason, http_resp)
def render_path(path_to_item):
"""Returns a string representation of a path"""
result = ""
for pth in path_to_item:
if isinstance(pth, int):
result += "[{0}]".format(pth)
else:
result += "['{0}']".format(pth)
return result

View File

@@ -0,0 +1,57 @@
#!/bin/sh
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
#
# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com"
git_user_id=$1
git_repo_id=$2
release_note=$3
git_host=$4
if [ "$git_host" = "" ]; then
git_host="{{{gitHost}}}"
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
fi
if [ "$git_user_id" = "" ]; then
git_user_id="{{{gitUserId}}}"
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi
if [ "$git_repo_id" = "" ]; then
git_repo_id="{{{gitRepoId}}}"
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi
if [ "$release_note" = "" ]; then
release_note="{{{releaseNote}}}"
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
fi
# Initialize the local directory as a Git repository
git init
# Adds the files in the local repository and stages them for commit.
git add .
# Commits the tracked changes and prepares them to be pushed to a remote repository.
git commit -m "$release_note"
# Sets the new remote
git_remote=$(git remote)
if [ "$git_remote" = "" ]; then # git remote not defined
if [ "$GIT_TOKEN" = "" ]; then
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git
fi
fi
git pull origin master
# Pushes (Forces) the changes in the local repository up to the remote repository
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View File

@@ -0,0 +1,38 @@
# NOTE: This file is auto generated by OpenAPI Generator.
# URL: https://openapi-generator.tech
#
# ref: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
name: {{packageName}} Python package
{{=<% %>=}}
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:s
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}s
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest

View File

@@ -0,0 +1,66 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
venv/
.venv/
.python-version
.pytest_cache
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#Ipython Notebook
.ipynb_checkpoints

View File

@@ -0,0 +1,25 @@
# NOTE: This file is auto generated by OpenAPI Generator.
# URL: https://openapi-generator.tech
#
# ref: https://docs.gitlab.com/ee/ci/README.html
# ref: https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Python.gitlab-ci.yml
stages:
- test
.pytest:
stage: test
script:
- pip install -r requirements.txt
- pip install -r test-requirements.txt
- pytest --cov={{{packageName}}}
pytest-3.7:
extends: .pytest
image: python:3.7-alpine
pytest-3.8:
extends: .pytest
image: python:3.8-alpine
pytest-3.9:
extends: .pytest
image: python:3.9-alpine

View File

@@ -0,0 +1,14 @@
# coding: utf-8
{{>partial_header}}
{{#models}}
{{#model}}
{{#isEnum}}
{{>model_enum}}
{{/isEnum}}
{{^isEnum}}
{{#oneOf}}{{#-first}}{{>model_oneof}}{{/-first}}{{/oneOf}}{{^oneOf}}{{#anyOf}}{{#-first}}{{>model_anyof}}{{/-first}}{{/anyOf}}{{^anyOf}}{{>model_generic}}{{/anyOf}}{{/oneOf}}
{{/isEnum}}
{{/model}}
{{/models}}

View File

@@ -0,0 +1,95 @@
from __future__ import annotations
from inspect import getfullargspec
import pprint
import re # noqa: F401
{{#vendorExtensions.x-py-datetime-imports}}{{#-first}}from datetime import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-datetime-imports}}
{{#vendorExtensions.x-py-typing-imports}}{{#-first}}from typing import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-typing-imports}}
{{#vendorExtensions.x-py-pydantic-imports}}{{#-first}}from pydantic import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-pydantic-imports}}
{{#vendorExtensions.x-py-model-imports}}
{{{.}}}
{{/vendorExtensions.x-py-model-imports}}
from typing import Any, List
from pydantic import StrictStr, Field
{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ANY_OF_SCHEMAS = [{{#anyOf}}"{{.}}"{{^-last}}, {{/-last}}{{/anyOf}}]
class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
{{#composedSchemas.anyOf}}
# data type: {{{dataType}}}
{{vendorExtensions.x-py-name}}: {{{vendorExtensions.x-py-typing}}}
{{/composedSchemas.anyOf}}
actual_instance: Any
any_of_schemas: List[str] = Field({{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ANY_OF_SCHEMAS, const=True)
class Config:
validate_assignment = True
{{#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}}
@validator('actual_instance')
def actual_instance_must_validate_anyof(cls, v):
error_messages = []
{{#composedSchemas.anyOf}}
# validate data type: {{{dataType}}}
if type(v) is not {{^isPrimitiveType}}{{/isPrimitiveType}}{{{dataType}}}:
error_messages.append(f"Error! Input type `{type(v)}` is not `{{{dataType}}}`")
else:
return v
{{/composedSchemas.anyOf}}
if error_messages:
# no match
raise ValueError("No match found when deserializing the JSON string into {{{classname}}} with anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}. Details: " + ", ".join(error_messages))
else:
return v
@classmethod
def from_json(cls, json_str: str) -> {{{classname}}}:
"""Returns the object represented by the json string"""
instance = cls()
error_messages = []
{{#composedSchemas.anyOf}}
{{^isPrimitiveType}}
# {{vendorExtensions.x-py-name}}: {{{vendorExtensions.x-py-typing}}}
try:
instance.actual_instance = {{{dataType}}}.from_json(json_str)
return instance
except ValidationError as e:
error_messages.append(str(e))
{{/isPrimitiveType}}
{{/composedSchemas.anyOf}}
if error_messages:
# no match
raise ValueError("No match found when deserializing the JSON string into {{{classname}}} with anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}. Details: " + ", ".join(error_messages))
else:
return instance
def to_json(self) -> str:
"""Returns the JSON representation of the actual instance"""
if self.actual_instance is not None:
return self.actual_instance.to_json()
else:
return "null"
def to_dict(self) -> dict:
"""Returns the dict representation of the actual instance"""
if self.actual_instance is not None:
return self.actual_instance.to_dict()
else:
return dict()
def to_str(self) -> str:
"""Returns the string representation of the actual instance"""
return pprint.pformat(self.dict())

View File

@@ -0,0 +1,33 @@
{{#models}}{{#model}}# {{classname}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#isReadOnly}}[readonly] {{/isReadOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
{{/vars}}
{{^isEnum}}
## Example
```python
from {{modelPackage}}.{{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}} import {{classname}}
# TODO update the JSON string below
json = "{}"
# create an instance of {{classname}} from a JSON string
{{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}}_instance = {{classname}}.from_json(json)
# print the JSON string representation of the object
print {{classname}}.to_json()
# convert the object into a dict
{{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}}_dict = {{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}}_instance.to_dict()
# create an instance of {{classname}} from a dict
{{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}}_form_dict = {{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}}.from_dict({{#lambda.snakecase}}{{classname}}{{/lambda.snakecase}}_dict)
```
{{/isEnum}}
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
{{/model}}{{/models}}

View File

@@ -0,0 +1,32 @@
from inspect import getfullargspec
import pprint
import re # noqa: F401
from aenum import Enum, no_arg
{{#vendorExtensions.x-py-datetime-imports}}{{#-first}}from datetime import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-datetime-imports}}
{{#vendorExtensions.x-py-typing-imports}}{{#-first}}from typing import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-typing-imports}}
{{#vendorExtensions.x-py-pydantic-imports}}{{#-first}}from pydantic import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-pydantic-imports}}
class {{classname}}({{vendorExtensions.x-py-enum-type}}, Enum):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
"""
allowed enum values
"""
{{#allowableValues}}
{{#enumVars}}
{{{name}}} = {{{value}}}
{{/enumVars}}
{{#defaultValue}}
#
@classmethod
def _missing_value_(cls, value):
if value is no_arg:
return cls.{{{.}}}
{{/defaultValue}}
{{/allowableValues}}

View File

@@ -0,0 +1,258 @@
from __future__ import annotations
from inspect import getfullargspec
import pprint
import re # noqa: F401
import json
{{#hasChildren}}
{{#discriminator}}
import {{{modelPackage}}}
{{/discriminator}}
{{/hasChildren}}
{{#vendorExtensions.x-py-datetime-imports}}{{#-first}}from datetime import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-datetime-imports}}
{{#vendorExtensions.x-py-typing-imports}}{{#-first}}from typing import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-typing-imports}}
{{#vendorExtensions.x-py-pydantic-imports}}{{#-first}}from pydantic import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-pydantic-imports}}
{{#vendorExtensions.x-py-model-imports}}
{{{.}}}
{{/vendorExtensions.x-py-model-imports}}
class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
{{#vars}}
{{name}}: {{{vendorExtensions.x-py-typing}}}
{{/vars}}
{{#isAdditionalPropertiesTrue}}
additional_properties: Dict[str, Any] = {}
{{/isAdditionalPropertiesTrue}}
__properties = [{{#allVars}}"{{baseName}}"{{^-last}}, {{/-last}}{{/allVars}}]
{{#vars}}
{{#vendorExtensions.x-regex}}
@validator('{{{name}}}')
def {{{name}}}_validate_regular_expression(cls, v):
if not re.match(r"{{{.}}}", v{{#vendorExtensions.x-modifiers}} ,re.{{{.}}}{{/vendorExtensions.x-modifiers}}):
raise ValueError(r"must validate the regular expression {{{pattern}}}")
return v
{{/vendorExtensions.x-regex}}
{{#isEnum}}
@validator('{{{name}}}')
def {{{name}}}_validate_enum(cls, v):
{{^required}}
if v is None:
return v
{{/required}}
if v not in ({{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}}):
raise ValueError("must validate the enum values ({{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}})")
return v
{{/isEnum}}
{{/vars}}
class Config:
allow_population_by_field_name = True
validate_assignment = True
{{#hasChildren}}
{{#discriminator}}
# JSON field name that stores the object type
__discriminator_property_name = '{{discriminator.propertyBaseName}}'
{{#mappedModels}}
{{#-first}}
# discriminator mappings
__discriminator_value_class_map = {
{{/-first}}
'{{{mappingName}}}': '{{{modelName}}}'{{^-last}},{{/-last}}
{{#-last}}
}
@classmethod
def get_discriminator_value(cls, obj: dict) -> str:
"""Returns the discriminator value (object type) of the data"""
discriminator_value = obj[cls.__discriminator_property_name]
if discriminator_value:
return cls.__discriminator_value_class_map.get(discriminator_value)
else:
return None
{{/-last}}
{{/mappedModels}}
{{/discriminator}}
{{/hasChildren}}
def to_str(self) -> str:
"""Returns the string representation of the model using alias"""
return pprint.pformat(self.dict(by_alias=True))
def to_json(self) -> str:
"""Returns the JSON representation of the model using alias"""
return json.dumps(self.to_dict())
@classmethod
def from_json(cls, json_str: str) -> {{^hasChildren}}{{{classname}}}{{/hasChildren}}{{#hasChildren}}{{#discriminator}}Union({{#children}}{{{classname}}}{{^-last}}, {{/-last}}{{/children}}){{/discriminator}}{{^discriminator}}{{{classname}}}{{/discriminator}}{{/hasChildren}}:
"""Create an instance of {{{classname}}} from a JSON string"""
return cls.from_dict(json.loads(json_str))
def to_dict(self):
"""Returns the dictionary representation of the model using alias"""
_dict = self.dict(by_alias=True,
exclude={
{{#vendorExtensions.x-py-readonly}}
"{{{.}}}",
{{/vendorExtensions.x-py-readonly}}
{{#isAdditionalPropertiesTrue}}
"additional_properties"
{{/isAdditionalPropertiesTrue}}
},
exclude_none=True)
{{#allVars}}
{{#isContainer}}
{{#isArray}}
{{^items.isPrimitiveType}}
{{^items.isEnumOrRef}}
# override the default output from pydantic by calling `to_dict()` of each item in {{{name}}} (list)
_items = []
if self.{{{name}}}:
for _item in self.{{{name}}}:
if _item:
_items.append(_item.to_dict())
_dict['{{{baseName}}}'] = _items
{{/items.isEnumOrRef}}
{{/items.isPrimitiveType}}
{{/isArray}}
{{#isMap}}
{{^items.isPrimitiveType}}
{{^items.isEnumOrRef}}
# override the default output from pydantic by calling `to_dict()` of each value in {{{name}}} (dict)
_field_dict = {}
if self.{{{name}}}:
for _key in self.{{{name}}}:
if self.{{{name}}}[_key]:
_field_dict[_key] = self.{{{name}}}[_key].to_dict()
_dict['{{{baseName}}}'] = _field_dict
{{/items.isEnumOrRef}}
{{/items.isPrimitiveType}}
{{/isMap}}
{{/isContainer}}
{{^isContainer}}
{{^isPrimitiveType}}
{{^isEnumOrRef}}
# override the default output from pydantic by calling `to_dict()` of {{{name}}}
if self.{{{name}}}:
_dict['{{{baseName}}}'] = self.{{{name}}}.to_dict()
{{/isEnumOrRef}}
{{/isPrimitiveType}}
{{/isContainer}}
{{/allVars}}
{{#isAdditionalPropertiesTrue}}
# puts key-value pairs in additional_properties in the top level
if self.additional_properties is not None:
for _key, _value in self.additional_properties.items():
_dict[_key] = _value
{{/isAdditionalPropertiesTrue}}
{{#allVars}}
{{#isNullable}}
# set to None if {{{name}}} (nullable) is None
if self.{{name}} is None:
_dict['{{{baseName}}}'] = None
{{/isNullable}}
{{/allVars}}
return _dict
@classmethod
def from_dict(cls, obj: dict) -> {{^hasChildren}}{{{classname}}}{{/hasChildren}}{{#hasChildren}}{{#discriminator}}Union({{#children}}{{{classname}}}{{^-last}}, {{/-last}}{{/children}}){{/discriminator}}{{^discriminator}}{{{classname}}}{{/discriminator}}{{/hasChildren}}:
"""Create an instance of {{{classname}}} from a dict"""
{{#hasChildren}}
{{#discriminator}}
# look up the object type based on discriminator mapping
object_type = cls.get_discriminator_value(obj)
if object_type:
klass = getattr({{modelPackage}}, object_type)
return klass.from_dict(obj)
else:
raise ValueError("{{{classname}}} failed to lookup discriminator value from " +
json.dumps(obj) + ". Discriminator property name: " + cls.__discriminator_property_name +
", mapping: " + json.dumps(cls.__discriminator_value_class_map))
{{/discriminator}}
{{/hasChildren}}
{{^hasChildren}}
if obj is None:
return None
if type(obj) is not dict:
return {{{classname}}}.parse_obj(obj)
{{#disallowAdditionalPropertiesIfNotPresent}}
{{^isAdditionalPropertiesTrue}}
# raise errors for additional fields in the input
for _key in obj.keys():
if _key not in cls.__properties:
raise ValueError("Error due to additional fields (not defined in {{classname}}) in the input: " + obj)
{{/isAdditionalPropertiesTrue}}
{{/disallowAdditionalPropertiesIfNotPresent}}
_obj = {{{classname}}}.parse_obj({
{{#allVars}}
{{#isContainer}}
{{#isArray}}
{{^items.isPrimitiveType}}
{{#items.isEnumOrRef}}
"{{{name}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}}
{{/items.isEnumOrRef}}
{{^items.isEnumOrRef}}
"{{{name}}}": [{{{items.dataType}}}.from_dict(_item) for _item in obj.get("{{{baseName}}}")] if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}}
{{/items.isEnumOrRef}}
{{/items.isPrimitiveType}}
{{#items.isPrimitiveType}}
"{{{name}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}}
{{/items.isPrimitiveType}}
{{/isArray}}
{{#isMap}}
{{^items.isPrimitiveType}}
{{^items.isEnumOrRef}}
"{{{name}}}": dict((_k, {{{dataType}}}.from_dict(_v)) for _k, _v in obj.get("{{{baseName}}}").items()){{^-last}},{{/-last}}
{{/items.isEnumOrRef}}
{{#items.isEnumOrRef}}
"{{{name}}}": dict((_k, _v) for _k, _v in obj.get("{{{baseName}}}").items()){{^-last}},{{/-last}}
{{/items.isEnumOrRef}}
{{/items.isPrimitiveType}}
{{#items.isPrimitiveType}}
"{{{name}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}}
{{/items.isPrimitiveType}}
{{/isMap}}
{{/isContainer}}
{{^isContainer}}
{{^isPrimitiveType}}
{{^isEnumOrRef}}
"{{{name}}}": {{{dataType}}}.from_dict(obj.get("{{{baseName}}}")) if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}}
{{/isEnumOrRef}}
{{#isEnumOrRef}}
"{{{name}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}}
{{/isEnumOrRef}}
{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{#defaultValue}}
"{{{name}}}": obj.get("{{{baseName}}}") if obj.get("{{{baseName}}}") is not None else {{{defaultValue}}}{{^-last}},{{/-last}}
{{/defaultValue}}
{{^defaultValue}}
"{{{name}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}}
{{/defaultValue}}
{{/isPrimitiveType}}
{{/isContainer}}
{{/allVars}}
})
{{#isAdditionalPropertiesTrue}}
# store additional fields in additional_properties
for _key in obj.keys():
if _key not in cls.__properties:
_obj.additional_properties[_key] = obj.get(_key)
{{/isAdditionalPropertiesTrue}}
return _obj
{{/hasChildren}}

View File

@@ -0,0 +1,131 @@
from __future__ import annotations
from inspect import getfullargspec
import pprint
import json
import re # noqa: F401
{{#vendorExtensions.x-py-datetime-imports}}{{#-first}}from datetime import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-datetime-imports}}
{{#vendorExtensions.x-py-typing-imports}}{{#-first}}from typing import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-typing-imports}}
{{#vendorExtensions.x-py-pydantic-imports}}{{#-first}}from pydantic import{{/-first}} {{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-py-pydantic-imports}}
{{#vendorExtensions.x-py-model-imports}}
{{{.}}}
{{/vendorExtensions.x-py-model-imports}}
from typing import Any, List
from pydantic import StrictStr, Field
{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ONE_OF_SCHEMAS = [{{#oneOf}}"{{.}}"{{^-last}}, {{/-last}}{{/oneOf}}]
class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
{{#composedSchemas.oneOf}}
# data type: {{{dataType}}}
{{vendorExtensions.x-py-name}}: {{{vendorExtensions.x-py-typing}}}
{{/composedSchemas.oneOf}}
actual_instance: Any
one_of_schemas: List[str] = Field({{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ONE_OF_SCHEMAS, const=True)
class Config:
validate_assignment = True
{{#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}}
@validator('actual_instance')
def actual_instance_must_validate_oneof(cls, v):
error_messages = []
match = 0
{{#composedSchemas.oneOf}}
# validate data type: {{{dataType}}}
if type(v) is not {{^isPrimitiveType}}{{/isPrimitiveType}}{{{dataType}}}:
error_messages.append(f"Error! Input type `{type(v)}` is not `{{{dataType}}}`")
else:
match += 1
{{/composedSchemas.oneOf}}
if match > 1:
# more than 1 match
raise ValueError("Multiple matches found when deserializing the JSON string into {{{classname}}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Details: " + ", ".join(error_messages))
elif match == 0:
# no match
raise ValueError("No match found when deserializing the JSON string into {{{classname}}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Details: " + ", ".join(error_messages))
else:
return v
@classmethod
def from_dict(cls, obj: dict) -> {{{classname}}}:
return cls.from_json(json.dumps(obj))
@classmethod
def from_json(cls, json_str: str) -> {{{classname}}}:
"""Returns the object represented by the json string"""
instance = cls()
error_messages = []
match = 0
{{#useOneOfDiscriminatorLookup}}
{{#discriminator}}
{{#mappedModels}}
{{#-first}}
# use oneOf discriminator to lookup the data type
_data_type = json.loads(json_str).get("{{{propertyBaseName}}}")
if not _data_type:
raise ValueError("Failed to lookup data type from the field `{{{propertyBaseName}}}` in the input.")
{{/-first}}
# check if data type is `{{{modelName}}}`
if _data_type == "{{{mappingName}}}":
instance.actual_instance = {{{modelName}}}.from_json(json_str)
return instance
{{/mappedModels}}
{{/discriminator}}
{{/useOneOfDiscriminatorLookup}}
{{#composedSchemas.oneOf}}
{{^isPrimitiveType}}
# deserialize data into {{{dataType}}}
try:
instance.actual_instance = {{{dataType}}}.from_json(json_str)
match += 1
except ValidationError as e:
error_messages.append(str(e))
{{/isPrimitiveType}}
{{/composedSchemas.oneOf}}
if match > 1:
# more than 1 match
raise ValueError("Multiple matches found when deserializing the JSON string into {{{classname}}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Details: " + ", ".join(error_messages))
elif match == 0:
# no match
raise ValueError("No match found when deserializing the JSON string into {{{classname}}} with oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Details: " + ", ".join(error_messages))
else:
return instance
def to_json(self) -> str:
"""Returns the JSON representation of the actual instance"""
if self.actual_instance is not None:
return self.actual_instance.to_json()
else:
return "null"
def to_dict(self) -> dict:
"""Returns the dict representation of the actual instance"""
if self.actual_instance is not None:
return self.actual_instance.to_dict()
else:
return dict()
def to_str(self) -> str:
"""Returns the string representation of the actual instance"""
return pprint.pformat(self.dict())

View File

@@ -0,0 +1,64 @@
# coding: utf-8
{{>partial_header}}
from __future__ import absolute_import
import unittest
import datetime
{{#models}}
{{#model}}
import {{packageName}}
from {{modelPackage}}.{{classFilename}} import {{classname}} # noqa: E501
from {{packageName}}.rest import ApiException
class Test{{classname}}(unittest.TestCase):
"""{{classname}} unit test stubs"""
def setUp(self):
pass
def tearDown(self):
pass
{{^isEnum}}
def make_instance(self, include_optional):
"""Test {{classname}}
include_option is a boolean, when False only required
params are included, when True both required and
optional params are included """
# uncomment below to create an instance of `{{{classname}}}`
"""
model = {{packageName}}.models.{{classFilename}}.{{classname}}() # noqa: E501
if include_optional :
return {{classname}}(
{{#vars}}
{{name}} = {{{example}}}{{^example}}None{{/example}}{{^-last}}, {{/-last}}
{{/vars}}
)
else :
return {{classname}}(
{{#vars}}
{{#required}}
{{name}} = {{{example}}}{{^example}}None{{/example}},
{{/required}}
{{/vars}}
)
"""
{{/isEnum}}
def test{{classname}}(self):
"""Test {{classname}}"""
{{^isEnum}}
# inst_req_only = self.make_instance(include_optional=False)
# inst_req_and_optional = self.make_instance(include_optional=True)
{{/isEnum}}
{{#isEnum}}
# inst = {{{classname}}}()
{{/isEnum}}
{{/model}}
{{/models}}
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,17 @@
"""
{{#appName}}
{{{.}}}
{{/appName}}
{{#appDescription}}
{{{.}}} # noqa: E501
{{/appDescription}}
{{#version}}
The version of the OpenAPI document: {{{.}}}
{{/version}}
{{#infoEmail}}
Contact: {{{.}}}
{{/infoEmail}}
Generated by: https://openapi-generator.tech
"""

View File

@@ -0,0 +1,105 @@
# Defining the host is optional and defaults to {{{basePath}}}
# See configuration.py for a list of all supported configuration parameters.
configuration = {{{packageName}}}.Configuration(
host = "{{{basePath}}}"
)
{{#hasAuthMethods}}
# The client must configure the authentication and authorization parameters
# in accordance with the API server security policy.
# Examples for each auth method are provided below, use the example that
# satisfies your auth use case.
{{#authMethods}}
{{#isBasic}}
{{#isBasicBasic}}
# Configure HTTP basic authorization: {{{name}}}
configuration = {{{packageName}}}.Configuration(
username = os.environ["USERNAME"],
password = os.environ["PASSWORD"]
)
{{/isBasicBasic}}
{{#isBasicBearer}}
# Configure Bearer authorization{{#bearerFormat}} ({{{.}}}){{/bearerFormat}}: {{{name}}}
configuration = {{{packageName}}}.Configuration(
access_token = os.environ["BEARER_TOKEN"]
)
{{/isBasicBearer}}
{{#isHttpSignature}}
# Configure HTTP message signature: {{{name}}}
# The HTTP Signature Header mechanism that can be used by a client to
# authenticate the sender of a message and ensure that particular headers
# have not been modified in transit.
#
# You can specify the signing key-id, private key path, signing scheme,
# signing algorithm, list of signed headers and signature max validity.
# The 'key_id' parameter is an opaque string that the API server can use
# to lookup the client and validate the signature.
# The 'private_key_path' parameter should be the path to a file that
# contains a DER or base-64 encoded private key.
# The 'private_key_passphrase' parameter is optional. Set the passphrase
# if the private key is encrypted.
# The 'signed_headers' parameter is used to specify the list of
# HTTP headers included when generating the signature for the message.
# You can specify HTTP headers that you want to protect with a cryptographic
# signature. Note that proxies may add, modify or remove HTTP headers
# for legitimate reasons, so you should only add headers that you know
# will not be modified. For example, if you want to protect the HTTP request
# body, you can specify the Digest header. In that case, the client calculates
# the digest of the HTTP request body and includes the digest in the message
# signature.
# The 'signature_max_validity' parameter is optional. It is configured as a
# duration to express when the signature ceases to be valid. The client calculates
# the expiration date every time it generates the cryptographic signature
# of an HTTP request. The API server may have its own security policy
# that controls the maximum validity of the signature. The client max validity
# must be lower than the server max validity.
# The time on the client and server must be synchronized, otherwise the
# server may reject the client signature.
#
# The client must use a combination of private key, signing scheme,
# signing algorithm and hash algorithm that matches the security policy of
# the API server.
#
# See {{{packageName}}}.signing for a list of all supported parameters.
configuration = {{{packageName}}}.Configuration(
host = "{{{basePath}}}",
signing_info = {{{packageName}}}.signing.HttpSigningConfiguration(
key_id = 'my-key-id',
private_key_path = 'private_key.pem',
private_key_passphrase = 'YOUR_PASSPHRASE',
signing_scheme = {{{packageName}}}.signing.SCHEME_HS2019,
signing_algorithm = {{{packageName}}}.signing.ALGORITHM_ECDSA_MODE_FIPS_186_3,
hash_algorithm = {{{packageName}}}.signing.SCHEME_RSA_SHA256,
signed_headers = [
{{{packageName}}}.signing.HEADER_REQUEST_TARGET,
{{{packageName}}}.signing.HEADER_CREATED,
{{{packageName}}}.signing.HEADER_EXPIRES,
{{{packageName}}}.signing.HEADER_HOST,
{{{packageName}}}.signing.HEADER_DATE,
{{{packageName}}}.signing.HEADER_DIGEST,
'Content-Type',
'Content-Length',
'User-Agent'
],
signature_max_validity = datetime.timedelta(minutes=5)
)
)
{{/isHttpSignature}}
{{/isBasic}}
{{#isApiKey}}
# Configure API key authorization: {{{name}}}
configuration.api_key['{{{name}}}'] = os.environ["API_KEY"]
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
# configuration.api_key_prefix['{{name}}'] = 'Bearer'
{{/isApiKey}}
{{#isOAuth}}
configuration.access_token = os.environ["ACCESS_TOKEN"]
{{/isOAuth}}
{{/authMethods}}
{{/hasAuthMethods}}

View File

@@ -0,0 +1,8 @@
python_dateutil >= 2.5.3
setuptools >= 21.0.0
urllib3 >= 1.25.3
pydantic >= 1.10.2
aenum >= 3.1.11
{{#asyncio}}
aiohttp >= 3.0.0
{{/asyncio}}

View File

@@ -0,0 +1,288 @@
# coding: utf-8
{{>partial_header}}
from __future__ import absolute_import
import io
import json
import logging
import re
import ssl
from urllib.parse import urlencode, quote_plus
import urllib3
from {{packageName}}.exceptions import ApiException, UnauthorizedException, ForbiddenException, NotFoundException, ServiceException, ApiValueError
logger = logging.getLogger(__name__)
class RESTResponse(io.IOBase):
def __init__(self, resp):
self.urllib3_response = resp
self.status = resp.status
self.reason = resp.reason
self.data = resp.data
def getheaders(self):
"""Returns a dictionary of the response headers."""
return self.urllib3_response.getheaders()
def getheader(self, name, default=None):
"""Returns a given response header."""
return self.urllib3_response.getheader(name, default)
class RESTClientObject(object):
def __init__(self, configuration, pools_size=4, maxsize=None):
# urllib3.PoolManager will pass all kw parameters to connectionpool
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501
# https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501
# maxsize is the number of requests to host that are allowed in parallel # noqa: E501
# Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501
# cert_reqs
if configuration.verify_ssl:
cert_reqs = ssl.CERT_REQUIRED
else:
cert_reqs = ssl.CERT_NONE
addition_pool_args = {}
if configuration.assert_hostname is not None:
addition_pool_args['assert_hostname'] = configuration.assert_hostname # noqa: E501
if configuration.retries is not None:
addition_pool_args['retries'] = configuration.retries
if configuration.socket_options is not None:
addition_pool_args['socket_options'] = configuration.socket_options
if maxsize is None:
if configuration.connection_pool_maxsize is not None:
maxsize = configuration.connection_pool_maxsize
else:
maxsize = 4
# https pool manager
if configuration.proxy:
self.pool_manager = urllib3.ProxyManager(
num_pools=pools_size,
maxsize=maxsize,
cert_reqs=cert_reqs,
ca_certs=configuration.ssl_ca_cert,
cert_file=configuration.cert_file,
key_file=configuration.key_file,
proxy_url=configuration.proxy,
proxy_headers=configuration.proxy_headers,
**addition_pool_args
)
else:
self.pool_manager = urllib3.PoolManager(
num_pools=pools_size,
maxsize=maxsize,
cert_reqs=cert_reqs,
ca_certs=configuration.ssl_ca_cert,
cert_file=configuration.cert_file,
key_file=configuration.key_file,
**addition_pool_args
)
def request(self, method, url, query_params=None, headers=None,
body=None, post_params=None, _preload_content=True,
_request_timeout=None):
"""Perform requests.
:param method: http request method
:param url: http request url
:param query_params: query parameters in the url
:param headers: http request headers
:param body: request json body, for `application/json`
:param post_params: request post parameters,
`application/x-www-form-urlencoded`
and `multipart/form-data`
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
"""
method = method.upper()
assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',
'PATCH', 'OPTIONS']
if post_params and body:
raise ApiValueError(
"body parameter cannot be used with post_params parameter."
)
post_params = post_params or {}
headers = headers or {}
# url already contains the URL query string
# so reset query_params to empty dict
query_params = {}
timeout = None
if _request_timeout:
if isinstance(_request_timeout, (int,float)): # noqa: E501,F821
timeout = urllib3.Timeout(total=_request_timeout)
elif (isinstance(_request_timeout, tuple) and
len(_request_timeout) == 2):
timeout = urllib3.Timeout(
connect=_request_timeout[0], read=_request_timeout[1])
try:
# For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
# no content type provided or payload is json
if not headers.get('Content-Type') or re.search('json', headers['Content-Type'], re.IGNORECASE):
request_body = None
if body is not None:
request_body = json.dumps(body)
r = self.pool_manager.request(
method, url,
body=request_body,
preload_content=_preload_content,
timeout=timeout,
headers=headers)
elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501
r = self.pool_manager.request(
method, url,
fields=post_params,
encode_multipart=False,
preload_content=_preload_content,
timeout=timeout,
headers=headers)
elif headers['Content-Type'] == 'multipart/form-data':
# must del headers['Content-Type'], or the correct
# Content-Type which generated by urllib3 will be
# overwritten.
del headers['Content-Type']
r = self.pool_manager.request(
method, url,
fields=post_params,
encode_multipart=True,
preload_content=_preload_content,
timeout=timeout,
headers=headers)
# Pass a `string` parameter directly in the body to support
# other content types than Json when `body` argument is
# provided in serialized form
elif isinstance(body, str) or isinstance(body, bytes):
request_body = body
r = self.pool_manager.request(
method, url,
body=request_body,
preload_content=_preload_content,
timeout=timeout,
headers=headers)
else:
# Cannot generate the request from given parameters
msg = """Cannot prepare a request message for provided
arguments. Please check that your arguments match
declared content type."""
raise ApiException(status=0, reason=msg)
# For `GET`, `HEAD`
else:
r = self.pool_manager.request(method, url,
fields={},
preload_content=_preload_content,
timeout=timeout,
headers=headers)
except urllib3.exceptions.SSLError as e:
msg = "{0}\n{1}".format(type(e).__name__, str(e))
raise ApiException(status=0, reason=msg)
if _preload_content:
r = RESTResponse(r)
# log response body
logger.debug("response body: %s", r.data)
if not 200 <= r.status <= 299:
if r.status == 401:
raise UnauthorizedException(http_resp=r)
if r.status == 403:
raise ForbiddenException(http_resp=r)
if r.status == 404:
raise NotFoundException(http_resp=r)
if 500 <= r.status <= 599:
raise ServiceException(http_resp=r)
raise ApiException(http_resp=r)
return r
def get_request(self, url, headers=None, query_params=None, _preload_content=True,
_request_timeout=None):
return self.request("GET", url,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
query_params=query_params)
def head_request(self, url, headers=None, query_params=None, _preload_content=True,
_request_timeout=None):
return self.request("HEAD", url,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
query_params=query_params)
def options_request(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
return self.request("OPTIONS", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
def delete_request(self, url, headers=None, query_params=None, body=None,
_preload_content=True, _request_timeout=None):
return self.request("DELETE", url,
headers=headers,
query_params=query_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
def post_request(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
return self.request("POST", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
def put_request(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
return self.request("PUT", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
def patch_request(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
return self.request("PATCH", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)

View File

@@ -0,0 +1,55 @@
# coding: utf-8
{{>partial_header}}
from setuptools import setup, find_packages # noqa: H301
# To install the library, run the following
#
# python setup.py install
#
# prerequisite: setuptools
# http://pypi.python.org/pypi/setuptools
NAME = "{{{projectName}}}"
VERSION = "{{packageVersion}}"
PYTHON_REQUIRES = ">=3.7"
{{#apiInfo}}
{{#apis}}
{{#-last}}
REQUIRES = [
"urllib3 >= 1.25.3",
"python-dateutil",
{{#asyncio}}
"aiohttp >= 3.0.0",
{{/asyncio}}
{{#tornado}}
"tornado>=4.2,<5",
{{/tornado}}
{{#hasHttpSignatureMethods}}
"pem>=19.3.0",
"pycryptodome>=3.9.0",
{{/hasHttpSignatureMethods}}
"pydantic",
"aenum"
]
setup(
name=NAME,
version=VERSION,
description="{{appName}}",
author="{{infoName}}{{^infoName}}OpenAPI Generator community{{/infoName}}",
author_email="{{infoEmail}}{{^infoEmail}}team@openapitools.org{{/infoEmail}}",
url="{{packageUrl}}",
keywords=["OpenAPI", "OpenAPI-Generator", "{{{appName}}}"],
install_requires=REQUIRES,
packages=find_packages(exclude=["test", "tests"]),
include_package_data=True,
{{#licenseInfo}}license="{{.}}",
{{/licenseInfo}}long_description_content_type='text/markdown',
long_description="""\
{{appDescription}} # noqa: E501
"""
)
{{/-last}}
{{/apis}}
{{/apiInfo}}

View File

@@ -0,0 +1,2 @@
[flake8]
max-line-length=99

View File

@@ -0,0 +1,408 @@
{{>partial_header}}
from base64 import b64encode
from Crypto.IO import PEM, PKCS8
from Crypto.Hash import SHA256, SHA512
from Crypto.PublicKey import RSA, ECC
from Crypto.Signature import PKCS1_v1_5, pss, DSS
from email.utils import formatdate
import json
import os
import re
from time import time
from urllib.parse import urlencode, urlparse
# The constants below define a subset of HTTP headers that can be included in the
# HTTP signature scheme. Additional headers may be included in the signature.
# The '(request-target)' header is a calculated field that includes the HTTP verb,
# the URL path and the URL query.
HEADER_REQUEST_TARGET = '(request-target)'
# The time when the HTTP signature was generated.
HEADER_CREATED = '(created)'
# The time when the HTTP signature expires. The API server should reject HTTP requests
# that have expired.
HEADER_EXPIRES = '(expires)'
# The 'Host' header.
HEADER_HOST = 'Host'
# The 'Date' header.
HEADER_DATE = 'Date'
# When the 'Digest' header is included in the HTTP signature, the client automatically
# computes the digest of the HTTP request body, per RFC 3230.
HEADER_DIGEST = 'Digest'
# The 'Authorization' header is automatically generated by the client. It includes
# the list of signed headers and a base64-encoded signature.
HEADER_AUTHORIZATION = 'Authorization'
# The constants below define the cryptographic schemes for the HTTP signature scheme.
SCHEME_HS2019 = 'hs2019'
SCHEME_RSA_SHA256 = 'rsa-sha256'
SCHEME_RSA_SHA512 = 'rsa-sha512'
# The constants below define the signature algorithms that can be used for the HTTP
# signature scheme.
ALGORITHM_RSASSA_PSS = 'RSASSA-PSS'
ALGORITHM_RSASSA_PKCS1v15 = 'RSASSA-PKCS1-v1_5'
ALGORITHM_ECDSA_MODE_FIPS_186_3 = 'fips-186-3'
ALGORITHM_ECDSA_MODE_DETERMINISTIC_RFC6979 = 'deterministic-rfc6979'
ALGORITHM_ECDSA_KEY_SIGNING_ALGORITHMS = {
ALGORITHM_ECDSA_MODE_FIPS_186_3,
ALGORITHM_ECDSA_MODE_DETERMINISTIC_RFC6979
}
# The cryptographic hash algorithm for the message signature.
HASH_SHA256 = 'sha256'
HASH_SHA512 = 'sha512'
class HttpSigningConfiguration(object):
"""The configuration parameters for the HTTP signature security scheme.
The HTTP signature security scheme is used to sign HTTP requests with a private key
which is in possession of the API client.
An 'Authorization' header is calculated by creating a hash of select headers,
and optionally the body of the HTTP request, then signing the hash value using
a private key. The 'Authorization' header is added to outbound HTTP requests.
NOTE: This class is auto generated by OpenAPI Generator
Ref: https://openapi-generator.tech
Do not edit the class manually.
:param key_id: A string value specifying the identifier of the cryptographic key,
when signing HTTP requests.
:param signing_scheme: A string value specifying the signature scheme, when
signing HTTP requests.
Supported value are hs2019, rsa-sha256, rsa-sha512.
Avoid using rsa-sha256, rsa-sha512 as they are deprecated. These values are
available for server-side applications that only support the older
HTTP signature algorithms.
:param private_key_path: A string value specifying the path of the file containing
a private key. The private key is used to sign HTTP requests.
:param private_key_passphrase: A string value specifying the passphrase to decrypt
the private key.
:param signed_headers: A list of strings. Each value is the name of a HTTP header
that must be included in the HTTP signature calculation.
The two special signature headers '(request-target)' and '(created)' SHOULD be
included in SignedHeaders.
The '(created)' header expresses when the signature was created.
The '(request-target)' header is a concatenation of the lowercased :method, an
ASCII space, and the :path pseudo-headers.
When signed_headers is not specified, the client defaults to a single value,
'(created)', in the list of HTTP headers.
When SignedHeaders contains the 'Digest' value, the client performs the
following operations:
1. Calculate a digest of request body, as specified in RFC3230, section 4.3.2.
2. Set the 'Digest' header in the request body.
3. Include the 'Digest' header and value in the HTTP signature.
:param signing_algorithm: A string value specifying the signature algorithm, when
signing HTTP requests.
Supported values are:
1. For RSA keys: RSASSA-PSS, RSASSA-PKCS1-v1_5.
2. For ECDSA keys: fips-186-3, deterministic-rfc6979.
If None, the signing algorithm is inferred from the private key.
The default signing algorithm for RSA keys is RSASSA-PSS.
The default signing algorithm for ECDSA keys is fips-186-3.
:param hash_algorithm: The hash algorithm for the signature. Supported values are
sha256 and sha512.
If the signing_scheme is rsa-sha256, the hash algorithm must be set
to None or sha256.
If the signing_scheme is rsa-sha512, the hash algorithm must be set
to None or sha512.
:param signature_max_validity: The signature max validity, expressed as
a datetime.timedelta value. It must be a positive value.
"""
def __init__(self, key_id, signing_scheme, private_key_path,
private_key_passphrase=None,
signed_headers=None,
signing_algorithm=None,
hash_algorithm=None,
signature_max_validity=None):
self.key_id = key_id
if signing_scheme not in {SCHEME_HS2019, SCHEME_RSA_SHA256, SCHEME_RSA_SHA512}:
raise Exception("Unsupported security scheme: {0}".format(signing_scheme))
self.signing_scheme = signing_scheme
if not os.path.exists(private_key_path):
raise Exception("Private key file does not exist")
self.private_key_path = private_key_path
self.private_key_passphrase = private_key_passphrase
self.signing_algorithm = signing_algorithm
self.hash_algorithm = hash_algorithm
if signing_scheme == SCHEME_RSA_SHA256:
if self.hash_algorithm is None:
self.hash_algorithm = HASH_SHA256
elif self.hash_algorithm != HASH_SHA256:
raise Exception("Hash algorithm must be sha256 when security scheme is %s" %
SCHEME_RSA_SHA256)
elif signing_scheme == SCHEME_RSA_SHA512:
if self.hash_algorithm is None:
self.hash_algorithm = HASH_SHA512
elif self.hash_algorithm != HASH_SHA512:
raise Exception("Hash algorithm must be sha512 when security scheme is %s" %
SCHEME_RSA_SHA512)
elif signing_scheme == SCHEME_HS2019:
if self.hash_algorithm is None:
self.hash_algorithm = HASH_SHA256
elif self.hash_algorithm not in {HASH_SHA256, HASH_SHA512}:
raise Exception("Invalid hash algorithm")
if signature_max_validity is not None and signature_max_validity.total_seconds() < 0:
raise Exception("The signature max validity must be a positive value")
self.signature_max_validity = signature_max_validity
# If the user has not provided any signed_headers, the default must be set to '(created)',
# as specified in the 'HTTP signature' standard.
if signed_headers is None or len(signed_headers) == 0:
signed_headers = [HEADER_CREATED]
if self.signature_max_validity is None and HEADER_EXPIRES in signed_headers:
raise Exception(
"Signature max validity must be set when "
"'(expires)' signature parameter is specified")
if len(signed_headers) != len(set(signed_headers)):
raise Exception("Cannot have duplicates in the signed_headers parameter")
if HEADER_AUTHORIZATION in signed_headers:
raise Exception("'Authorization' header cannot be included in signed headers")
self.signed_headers = signed_headers
self.private_key = None
"""The private key used to sign HTTP requests.
Initialized when the PEM-encoded private key is loaded from a file.
"""
self.host = None
"""The host name, optionally followed by a colon and TCP port number.
"""
self._load_private_key()
def get_http_signature_headers(self, resource_path, method, headers, body, query_params):
"""Create a cryptographic message signature for the HTTP request and add the signed headers.
:param resource_path : A string representation of the HTTP request resource path.
:param method: A string representation of the HTTP request method, e.g. GET, POST.
:param headers: A dict containing the HTTP request headers.
:param body: The object representing the HTTP request body.
:param query_params: A string representing the HTTP request query parameters.
:return: A dict of HTTP headers that must be added to the outbound HTTP request.
"""
if method is None:
raise Exception("HTTP method must be set")
if resource_path is None:
raise Exception("Resource path must be set")
signed_headers_list, request_headers_dict = self._get_signed_header_info(
resource_path, method, headers, body, query_params)
header_items = [
"{0}: {1}".format(key.lower(), value) for key, value in signed_headers_list]
string_to_sign = "\n".join(header_items)
digest, digest_prefix = self._get_message_digest(string_to_sign.encode())
b64_signed_msg = self._sign_digest(digest)
request_headers_dict[HEADER_AUTHORIZATION] = self._get_authorization_header(
signed_headers_list, b64_signed_msg)
return request_headers_dict
def get_public_key(self):
"""Returns the public key object associated with the private key.
"""
pubkey = None
if isinstance(self.private_key, RSA.RsaKey):
pubkey = self.private_key.publickey()
elif isinstance(self.private_key, ECC.EccKey):
pubkey = self.private_key.public_key()
return pubkey
def _load_private_key(self):
"""Load the private key used to sign HTTP requests.
The private key is used to sign HTTP requests as defined in
https://datatracker.ietf.org/doc/draft-cavage-http-signatures/.
"""
if self.private_key is not None:
return
with open(self.private_key_path, 'r') as f:
pem_data = f.read()
# Verify PEM Pre-Encapsulation Boundary
r = re.compile(r"\s*-----BEGIN (.*)-----\s+")
m = r.match(pem_data)
if not m:
raise ValueError("Not a valid PEM pre boundary")
pem_header = m.group(1)
if pem_header == 'RSA PRIVATE KEY':
self.private_key = RSA.importKey(pem_data, self.private_key_passphrase)
elif pem_header == 'EC PRIVATE KEY':
self.private_key = ECC.import_key(pem_data, self.private_key_passphrase)
elif pem_header in {'PRIVATE KEY', 'ENCRYPTED PRIVATE KEY'}:
# Key is in PKCS8 format, which is capable of holding many different
# types of private keys, not just EC keys.
(key_binary, pem_header, is_encrypted) = \
PEM.decode(pem_data, self.private_key_passphrase)
(oid, privkey, params) = \
PKCS8.unwrap(key_binary, passphrase=self.private_key_passphrase)
if oid == '1.2.840.10045.2.1':
self.private_key = ECC.import_key(pem_data, self.private_key_passphrase)
else:
raise Exception("Unsupported key: {0}. OID: {1}".format(pem_header, oid))
else:
raise Exception("Unsupported key: {0}".format(pem_header))
# Validate the specified signature algorithm is compatible with the private key.
if self.signing_algorithm is not None:
supported_algs = None
if isinstance(self.private_key, RSA.RsaKey):
supported_algs = {ALGORITHM_RSASSA_PSS, ALGORITHM_RSASSA_PKCS1v15}
elif isinstance(self.private_key, ECC.EccKey):
supported_algs = ALGORITHM_ECDSA_KEY_SIGNING_ALGORITHMS
if supported_algs is not None and self.signing_algorithm not in supported_algs:
raise Exception(
"Signing algorithm {0} is not compatible with private key".format(
self.signing_algorithm))
def _get_signed_header_info(self, resource_path, method, headers, body, query_params):
"""Build the HTTP headers (name, value) that need to be included in
the HTTP signature scheme.
:param resource_path : A string representation of the HTTP request resource path.
:param method: A string representation of the HTTP request method, e.g. GET, POST.
:param headers: A dict containing the HTTP request headers.
:param body: The object (e.g. a dict) representing the HTTP request body.
:param query_params: A string representing the HTTP request query parameters.
:return: A tuple containing two dict objects:
The first dict contains the HTTP headers that are used to calculate
the HTTP signature.
The second dict contains the HTTP headers that must be added to
the outbound HTTP request.
"""
if body is None:
body = ''
else:
body = body.to_json()
# Build the '(request-target)' HTTP signature parameter.
target_host = urlparse(self.host).netloc
target_path = urlparse(self.host).path
request_target = method.lower() + " " + target_path + resource_path
if query_params:
request_target += "?" + urlencode(query_params)
# Get UNIX time, e.g. seconds since epoch, not including leap seconds.
now = time()
# Format date per RFC 7231 section-7.1.1.2. An example is:
# Date: Wed, 21 Oct 2015 07:28:00 GMT
cdate = formatdate(timeval=now, localtime=False, usegmt=True)
# The '(created)' value MUST be a Unix timestamp integer value.
# Subsecond precision is not supported.
created = int(now)
if self.signature_max_validity is not None:
expires = now + self.signature_max_validity.total_seconds()
signed_headers_list = []
request_headers_dict = {}
for hdr_key in self.signed_headers:
hdr_key = hdr_key.lower()
if hdr_key == HEADER_REQUEST_TARGET:
value = request_target
elif hdr_key == HEADER_CREATED:
value = '{0}'.format(created)
elif hdr_key == HEADER_EXPIRES:
value = '{0}'.format(expires)
elif hdr_key == HEADER_DATE.lower():
value = cdate
request_headers_dict[HEADER_DATE] = '{0}'.format(cdate)
elif hdr_key == HEADER_DIGEST.lower():
request_body = body.encode()
body_digest, digest_prefix = self._get_message_digest(request_body)
b64_body_digest = b64encode(body_digest.digest())
value = digest_prefix + b64_body_digest.decode('ascii')
request_headers_dict[HEADER_DIGEST] = '{0}{1}'.format(
digest_prefix, b64_body_digest.decode('ascii'))
elif hdr_key == HEADER_HOST.lower():
value = target_host
request_headers_dict[HEADER_HOST] = '{0}'.format(target_host)
else:
value = next((v for k, v in headers.items() if k.lower() == hdr_key), None)
if value is None:
raise Exception(
"Cannot sign HTTP request. "
"Request does not contain the '{0}' header".format(hdr_key))
signed_headers_list.append((hdr_key, value))
return signed_headers_list, request_headers_dict
def _get_message_digest(self, data):
"""Calculates and returns a cryptographic digest of a specified HTTP request.
:param data: The string representation of the date to be hashed with a cryptographic hash.
:return: A tuple of (digest, prefix).
The digest is a hashing object that contains the cryptographic digest of
the HTTP request.
The prefix is a string that identifies the cryptographic hash. It is used
to generate the 'Digest' header as specified in RFC 3230.
"""
if self.hash_algorithm == HASH_SHA512:
digest = SHA512.new()
prefix = 'SHA-512='
elif self.hash_algorithm == HASH_SHA256:
digest = SHA256.new()
prefix = 'SHA-256='
else:
raise Exception("Unsupported hash algorithm: {0}".format(self.hash_algorithm))
digest.update(data)
return digest, prefix
def _sign_digest(self, digest):
"""Signs a message digest with a private key specified in the signing_info.
:param digest: A hashing object that contains the cryptographic digest of the HTTP request.
:return: A base-64 string representing the cryptographic signature of the input digest.
"""
sig_alg = self.signing_algorithm
if isinstance(self.private_key, RSA.RsaKey):
if sig_alg is None or sig_alg == ALGORITHM_RSASSA_PSS:
# RSASSA-PSS in Section 8.1 of RFC8017.
signature = pss.new(self.private_key).sign(digest)
elif sig_alg == ALGORITHM_RSASSA_PKCS1v15:
# RSASSA-PKCS1-v1_5 in Section 8.2 of RFC8017.
signature = PKCS1_v1_5.new(self.private_key).sign(digest)
else:
raise Exception("Unsupported signature algorithm: {0}".format(sig_alg))
elif isinstance(self.private_key, ECC.EccKey):
if sig_alg is None:
sig_alg = ALGORITHM_ECDSA_MODE_FIPS_186_3
if sig_alg in ALGORITHM_ECDSA_KEY_SIGNING_ALGORITHMS:
# draft-ietf-httpbis-message-signatures-00 does not specify the ECDSA encoding.
# Issue: https://github.com/w3c-ccg/http-signatures/issues/107
signature = DSS.new(key=self.private_key, mode=sig_alg,
encoding='der').sign(digest)
else:
raise Exception("Unsupported signature algorithm: {0}".format(sig_alg))
else:
raise Exception("Unsupported private key: {0}".format(type(self.private_key)))
return b64encode(signature)
def _get_authorization_header(self, signed_headers, signed_msg):
"""Calculates and returns the value of the 'Authorization' header when signing HTTP requests.
:param signed_headers : A list of tuples. Each value is the name of a HTTP header that
must be included in the HTTP signature calculation.
:param signed_msg: A base-64 encoded string representation of the signature.
:return: The string value of the 'Authorization' header, representing the signature
of the HTTP request.
"""
created_ts = None
expires_ts = None
for k, v in signed_headers:
if k == HEADER_CREATED:
created_ts = v
elif k == HEADER_EXPIRES:
expires_ts = v
lower_keys = [k.lower() for k, v in signed_headers]
headers_value = " ".join(lower_keys)
auth_str = "Signature keyId=\"{0}\",algorithm=\"{1}\",".format(
self.key_id, self.signing_scheme)
if created_ts is not None:
auth_str = auth_str + "created={0},".format(created_ts)
if expires_ts is not None:
auth_str = auth_str + "expires={0},".format(expires_ts)
auth_str = auth_str + "headers=\"{0}\",signature=\"{1}\"".format(
headers_value, signed_msg.decode('ascii'))
return auth_str

View File

@@ -0,0 +1,6 @@
pytest~=7.1.3
pytest-cov>=2.8.1
pytest-randomly>=3.12.0
{{#hasHttpSignatureMethods}}
pycryptodome>=3.9.0
{{/hasHttpSignatureMethods}}

View File

@@ -0,0 +1,223 @@
# coding: utf-8
{{>partial_header}}
import io
import json
import logging
import re
from urllib.parse import urlencode, quote_plus
import tornado
import tornado.gen
from tornado import httpclient
from urllib3.filepost import encode_multipart_formdata
from {{packageName}}.exceptions import ApiException, ApiValueError
logger = logging.getLogger(__name__)
class RESTResponse(io.IOBase):
def __init__(self, resp):
self.tornado_response = resp
self.status = resp.code
self.reason = resp.reason
if resp.body:
self.data = resp.body
else:
self.data = None
def getheaders(self):
"""Returns a CIMultiDictProxy of the response headers."""
return self.tornado_response.headers
def getheader(self, name, default=None):
"""Returns a given response header."""
return self.tornado_response.headers.get(name, default)
class RESTClientObject(object):
def __init__(self, configuration, pools_size=4, maxsize=4):
# maxsize is number of requests to host that are allowed in parallel
self.ca_certs = configuration.ssl_ca_cert
self.client_key = configuration.key_file
self.client_cert = configuration.cert_file
self.proxy_port = self.proxy_host = None
# https pool manager
if configuration.proxy:
self.proxy_port = 80
self.proxy_host = configuration.proxy
self.pool_manager = httpclient.AsyncHTTPClient()
@tornado.gen.coroutine
def request(self, method, url, query_params=None, headers=None, body=None,
post_params=None, _preload_content=True,
_request_timeout=None):
"""Execute Request
:param method: http request method
:param url: http request url
:param query_params: query parameters in the url
:param headers: http request headers
:param body: request json body, for `application/json`
:param post_params: request post parameters,
`application/x-www-form-urlencoded`
and `multipart/form-data`
:param _preload_content: this is a non-applicable field for
the AiohttpClient.
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
"""
method = method.upper()
assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',
'PATCH', 'OPTIONS']
if post_params and body:
raise ApiValueError(
"body parameter cannot be used with post_params parameter."
)
request = httpclient.HTTPRequest(url)
request.allow_nonstandard_methods = True
request.ca_certs = self.ca_certs
request.client_key = self.client_key
request.client_cert = self.client_cert
request.proxy_host = self.proxy_host
request.proxy_port = self.proxy_port
request.method = method
if headers:
request.headers = headers
if 'Content-Type' not in headers:
request.headers['Content-Type'] = 'application/json'
request.request_timeout = _request_timeout or 5 * 60
post_params = post_params or {}
if query_params:
request.url += '?' + urlencode(query_params)
# For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
if re.search('json', headers['Content-Type'], re.IGNORECASE):
if body:
body = json.dumps(body)
request.body = body
elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501
request.body = urlencode(post_params)
elif headers['Content-Type'] == 'multipart/form-data':
multipart = encode_multipart_formdata(post_params)
request.body, headers['Content-Type'] = multipart
# Pass a `bytes` parameter directly in the body to support
# other content types than Json when `body` argument is provided
# in serialized form
elif isinstance(body, bytes):
request.body = body
else:
# Cannot generate the request from given parameters
msg = """Cannot prepare a request message for provided
arguments. Please check that your arguments match
declared content type."""
raise ApiException(status=0, reason=msg)
r = yield self.pool_manager.fetch(request, raise_error=False)
if _preload_content:
r = RESTResponse(r)
# log response body
logger.debug("response body: %s", r.data)
if not 200 <= r.status <= 299:
raise ApiException(http_resp=r)
raise tornado.gen.Return(r)
@tornado.gen.coroutine
def GET(self, url, headers=None, query_params=None, _preload_content=True,
_request_timeout=None):
result = yield self.request("GET", url,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
query_params=query_params)
raise tornado.gen.Return(result)
@tornado.gen.coroutine
def HEAD(self, url, headers=None, query_params=None, _preload_content=True,
_request_timeout=None):
result = yield self.request("HEAD", url,
headers=headers,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
query_params=query_params)
raise tornado.gen.Return(result)
@tornado.gen.coroutine
def OPTIONS(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
result = yield self.request("OPTIONS", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
raise tornado.gen.Return(result)
@tornado.gen.coroutine
def DELETE(self, url, headers=None, query_params=None, body=None,
_preload_content=True, _request_timeout=None):
result = yield self.request("DELETE", url,
headers=headers,
query_params=query_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
raise tornado.gen.Return(result)
@tornado.gen.coroutine
def POST(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
result = yield self.request("POST", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
raise tornado.gen.Return(result)
@tornado.gen.coroutine
def PUT(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
result = yield self.request("PUT", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
raise tornado.gen.Return(result)
@tornado.gen.coroutine
def PATCH(self, url, headers=None, query_params=None, post_params=None,
body=None, _preload_content=True, _request_timeout=None):
result = yield self.request("PATCH", url,
headers=headers,
query_params=query_params,
post_params=post_params,
_preload_content=_preload_content,
_request_timeout=_request_timeout,
body=body)
raise tornado.gen.Return(result)

View File

@@ -0,0 +1,9 @@
[tox]
envlist = py3
[testenv]
deps=-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands=
pytest --cov={{{packageName}}}

View File

@@ -0,0 +1,17 @@
# ref: https://docs.travis-ci.com/user/languages/python
language: python
python:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
# uncomment the following if needed
#- "3.11-dev" # 3.11 development branch
#- "nightly" # nightly build
# command to install dependencies
install:
- "pip install -r requirements.txt"
- "pip install -r test-requirements.txt"
# command to run tests
script: pytest --cov={{{packageName}}}

View File

@@ -255,7 +255,7 @@ public class PythonLegacyClientCodegenTest {
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "translations");
Assert.assertEquals(property1.dataType, "dict(str, str)");
Assert.assertEquals(property1.dataType, "dict[str, str]");
Assert.assertEquals(property1.name, "translations");
Assert.assertEquals(property1.baseType, "dict");
Assert.assertEquals(property1.containerType, "map");
@@ -335,7 +335,7 @@ public class PythonLegacyClientCodegenTest {
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.complexType, "Children");
Assert.assertEquals(property1.dataType, "dict(str, Children)");
Assert.assertEquals(property1.dataType, "dict[str, Children]");
Assert.assertEquals(property1.name, "children");
Assert.assertEquals(property1.baseType, "dict");
Assert.assertEquals(property1.containerType, "map");

View File

@@ -0,0 +1,385 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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.python;
import com.google.common.collect.Sets;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.PythonNextgenClientCodegen;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
public class PythonNextgenClientCodegenTest {
@Test
public void testInitialConfigValues() throws Exception {
final PythonNextgenClientCodegen codegen = new PythonNextgenClientCodegen();
codegen.processOpts();
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.TRUE);
Assert.assertEquals(codegen.isHideGenerationTimestamp(), true);
}
@Test
public void testSettersForConfigValues() throws Exception {
final PythonNextgenClientCodegen codegen = new PythonNextgenClientCodegen();
codegen.setHideGenerationTimestamp(false);
codegen.processOpts();
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.FALSE);
Assert.assertEquals(codegen.isHideGenerationTimestamp(), false);
}
@Test
public void testAdditionalPropertiesPutForConfigValues() throws Exception {
final PythonNextgenClientCodegen codegen = new PythonNextgenClientCodegen();
codegen.additionalProperties().put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, false);
codegen.processOpts();
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.FALSE);
Assert.assertEquals(codegen.isHideGenerationTimestamp(), false);
}
@Test(description = "test enum null/nullable patterns")
public void testEnumNull() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_1997.yaml");
StringSchema prop = (StringSchema) openAPI.getComponents().getSchemas().get("Type").getProperties().get("prop");
ArrayList<Object> expected = new ArrayList<>(Arrays.asList("A", "B", "C"));
assert prop.getNullable();
assert prop.getEnum().equals(expected);
}
@Test(description = "test regex patterns")
public void testRegularExpressionOpenAPISchemaVersion3() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_1517.yaml");
final PythonNextgenClientCodegen codegen = new PythonNextgenClientCodegen();
codegen.setOpenAPI(openAPI);
final String path = "/ping";
final Operation p = openAPI.getPaths().get(path).getGet();
final CodegenOperation op = codegen.fromOperation(path, "get", p, null);
// pattern_no_forward_slashes '^pattern$'
Assert.assertEquals(op.allParams.get(0).pattern, "/^pattern$/");
// pattern_two_slashes '/^pattern$/'
Assert.assertEquals(op.allParams.get(1).pattern, "/^pattern$/");
// pattern_dont_escape_backslash '/^pattern\d{3}$/'
Assert.assertEquals(op.allParams.get(2).pattern, "/^pattern\\d{3}$/");
// pattern_dont_escape_escaped_forward_slash '/^pattern\/\d{3}$/'
Assert.assertEquals(op.allParams.get(3).pattern, "/^pattern\\/\\d{3}$/");
// pattern_escape_unescaped_forward_slash '^pattern/\d{3}$'
Assert.assertEquals(op.allParams.get(4).pattern, "/^pattern\\/\\d{3}$/");
// pattern_with_modifiers '/^pattern\d{3}$/i
Assert.assertEquals(op.allParams.get(5).pattern, "/^pattern\\d{3}$/i");
// pattern_with_backslash_after_bracket '/^[\pattern\d{3}$/i'
// added to test fix for issue #6675
// removed because "/^[\\pattern\\d{3}$/i" is invalid regex because [ is not escaped and there is no closing ]
// Assert.assertEquals(op.allParams.get(6).pattern, "/^[\\pattern\\d{3}$/i");
}
@Test(description = "test generated example values for string properties")
public void testGeneratedExampleValues() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/examples.yaml");
final PythonNextgenClientCodegen codegen = new PythonNextgenClientCodegen();
codegen.setOpenAPI(openAPI);
final Schema dummyUserSchema = openAPI.getComponents().getSchemas().get("DummyUser");
final Schema nameSchema = (Schema) dummyUserSchema.getProperties().get("name");
final Schema numberSchema = (Schema) dummyUserSchema.getProperties().get("number");
final Schema addressSchema = (Schema) dummyUserSchema.getProperties().get("address");
final String namePattern = codegen.patternCorrection(nameSchema.getPattern());
final String numberPattern = codegen.patternCorrection(numberSchema.getPattern());
final String addressPattern = codegen.patternCorrection(addressSchema.getPattern());
Assert.assertTrue(codegen.escapeQuotationMark(codegen.toExampleValue(nameSchema)).matches(namePattern));
Assert.assertTrue(codegen.escapeQuotationMark(codegen.toExampleValue(numberSchema)).matches(numberPattern));
Assert.assertTrue(codegen.escapeQuotationMark(codegen.toExampleValue(addressSchema)).matches(addressPattern));
}
@Test(description = "test single quotes escape")
public void testSingleQuotes() {
final PythonNextgenClientCodegen codegen = new PythonNextgenClientCodegen();
StringSchema schema = new StringSchema();
schema.setDefault("Text containing 'single' quote");
String defaultValue = codegen.toDefaultValue(schema);
Assert.assertEquals("'Text containing \'single\' quote'", defaultValue);
}
@Test(description = "convert a python model with dots")
public void modelTest() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/2_0/v1beta3.json");
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOpenAPI(openAPI);
final CodegenModel simpleName = codegen.fromModel("v1beta3.Binding", openAPI.getComponents().getSchemas().get("v1beta3.Binding"));
Assert.assertEquals(simpleName.name, "v1beta3.Binding");
Assert.assertEquals(simpleName.classname, "V1beta3Binding");
Assert.assertEquals(simpleName.classVarName, "v1beta3_binding");
codegen.setOpenAPI(openAPI);
final CodegenModel compoundName = codegen.fromModel("v1beta3.ComponentStatus", openAPI.getComponents().getSchemas().get("v1beta3.ComponentStatus"));
Assert.assertEquals(compoundName.name, "v1beta3.ComponentStatus");
Assert.assertEquals(compoundName.classname, "V1beta3ComponentStatus");
Assert.assertEquals(compoundName.classVarName, "v1beta3_component_status");
final String path = "/api/v1beta3/namespaces/{namespaces}/bindings";
final Operation operation = openAPI.getPaths().get(path).getPost();
final CodegenOperation codegenOperation = codegen.fromOperation(path, "get", operation, null);
Assert.assertEquals(codegenOperation.returnType, "V1beta3Binding");
Assert.assertEquals(codegenOperation.returnBaseType, "V1beta3Binding");
}
@Test(description = "convert a simple java model")
public void simpleModelTest() {
final Schema schema = new Schema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT))
.addProperties("name", new StringSchema())
.addProperties("createdAt", new DateTimeSchema())
.addRequiredItem("id")
.addRequiredItem("name");
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", schema);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", schema);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 3);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
Assert.assertEquals(property1.dataType, "int");
Assert.assertEquals(property1.name, "id");
Assert.assertNull(property1.defaultValue);
Assert.assertEquals(property1.baseType, "int");
Assert.assertTrue(property1.required);
Assert.assertTrue(property1.isPrimitiveType);
final CodegenProperty property2 = cm.vars.get(1);
Assert.assertEquals(property2.baseName, "name");
Assert.assertEquals(property2.dataType, "str");
Assert.assertEquals(property2.name, "name");
Assert.assertNull(property2.defaultValue);
Assert.assertEquals(property2.baseType, "str");
Assert.assertTrue(property2.required);
Assert.assertTrue(property2.isPrimitiveType);
final CodegenProperty property3 = cm.vars.get(2);
Assert.assertEquals(property3.baseName, "createdAt");
Assert.assertEquals(property3.dataType, "datetime");
Assert.assertEquals(property3.name, "created_at");
Assert.assertNull(property3.defaultValue);
Assert.assertEquals(property3.baseType, "datetime");
Assert.assertFalse(property3.required);
}
@Test(description = "convert a model with list property")
public void listPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT))
.addProperties("urls", new ArraySchema()
.items(new StringSchema()))
.addRequiredItem("id");
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 2);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
Assert.assertEquals(property1.dataType, "int");
Assert.assertEquals(property1.name, "id");
Assert.assertNull(property1.defaultValue);
Assert.assertEquals(property1.baseType, "int");
Assert.assertTrue(property1.required);
Assert.assertTrue(property1.isPrimitiveType);
final CodegenProperty property2 = cm.vars.get(1);
Assert.assertEquals(property2.baseName, "urls");
Assert.assertEquals(property2.dataType, "List[str]");
Assert.assertEquals(property2.name, "urls");
Assert.assertNull(property2.defaultValue);
Assert.assertEquals(property2.baseType, "List");
Assert.assertEquals(property2.containerType, "array");
Assert.assertFalse(property2.required);
Assert.assertTrue(property2.isPrimitiveType);
Assert.assertTrue(property2.isContainer);
}
@Test(description = "convert a model with a map property")
public void mapPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("translations", new MapSchema()
.additionalProperties(new StringSchema()))
.addRequiredItem("id");
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "translations");
Assert.assertEquals(property1.dataType, "Dict[str, str]");
Assert.assertEquals(property1.name, "translations");
Assert.assertEquals(property1.baseType, "Dict");
Assert.assertEquals(property1.containerType, "map");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isContainer);
Assert.assertTrue(property1.isPrimitiveType);
}
@Test(description = "convert a model with complex property")
public void complexPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("children", new Schema().$ref("#/definitions/Children"));
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.dataType, "Children");
Assert.assertEquals(property1.name, "children");
Assert.assertEquals(property1.baseType, "Children");
Assert.assertFalse(property1.required);
Assert.assertFalse(property1.isContainer);
}
@Test(description = "convert a model with complex list property")
public void complexListPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("children", new ArraySchema()
.items(new Schema().$ref("#/definitions/Children")));
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.complexType, "Children");
Assert.assertEquals(property1.dataType, "List[Children]");
Assert.assertEquals(property1.name, "children");
Assert.assertEquals(property1.baseType, "List");
Assert.assertEquals(property1.containerType, "array");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isContainer);
}
@Test(description = "convert a model with complex map property")
public void complexMapPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("children", new MapSchema()
.additionalProperties(new Schema().$ref("#/definitions/Children")));
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.complexType, "Children");
Assert.assertEquals(property1.dataType, "Dict[str, Children]");
Assert.assertEquals(property1.name, "children");
Assert.assertEquals(property1.baseType, "Dict");
Assert.assertEquals(property1.containerType, "map");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isContainer);
}
// should not start with 'null'. need help from the community to investigate further
@Test(description = "convert an array model")
public void arrayModelTest() {
final Schema model = new ArraySchema()
//.description()
.items(new Schema().$ref("#/definitions/Children"))
.description("an array model");
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "an array model");
Assert.assertEquals(cm.vars.size(), 0);
Assert.assertEquals(cm.parent, "null<Children>");
Assert.assertEquals(cm.imports.size(), 1);
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
}
// should not start with 'null'. need help from the community to investigate further
@Test(description = "convert a map model")
public void mapModelTest() {
final Schema model = new Schema()
.description("a map model")
.additionalProperties(new Schema().$ref("#/definitions/Children"));
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
codegen.setOpenAPI(openAPI);
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a map model");
Assert.assertEquals(cm.vars.size(), 0);
Assert.assertEquals(cm.parent, null);
Assert.assertEquals(cm.imports.size(), 0);
}
}

View File

@@ -1224,6 +1224,8 @@
</activation>
<modules>
<!-- clients -->
<module>samples/openapi3/client/petstore/python-nextgen</module>
<module>samples/openapi3/client/petstore/python-nextgen-aiohttp</module>
<module>samples/client/petstore/python-prior</module>
<module>samples/client/petstore/python-prior_disallowAdditionalPropertiesIfNotPresent</module>
<!--<module>samples/openapi3/client/petstore/python-legacy</module>-->

View File

@@ -4,14 +4,14 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_string** | **dict(str, str)** | | [optional]
**map_number** | **dict(str, float)** | | [optional]
**map_integer** | **dict(str, int)** | | [optional]
**map_boolean** | **dict(str, bool)** | | [optional]
**map_array_integer** | **dict(str, list[int])** | | [optional]
**map_array_anytype** | **dict(str, list[object])** | | [optional]
**map_map_string** | **dict(str, dict(str, str))** | | [optional]
**map_map_anytype** | **dict(str, dict(str, object))** | | [optional]
**map_string** | **dict[str, str]** | | [optional]
**map_number** | **dict[str, float]** | | [optional]
**map_integer** | **dict[str, int]** | | [optional]
**map_boolean** | **dict[str, bool]** | | [optional]
**map_array_integer** | **dict[str, list[int]]** | | [optional]
**map_array_anytype** | **dict[str, list[object]]** | | [optional]
**map_map_string** | **dict[str, dict[str, str]]** | | [optional]
**map_map_anytype** | **dict[str, dict[str, object]]** | | [optional]
**anytype_1** | **object** | | [optional]
**anytype_2** | **object** | | [optional]
**anytype_3** | **object** | | [optional]

View File

@@ -777,7 +777,7 @@ configuration = petstore_api.Configuration(
with petstore_api.ApiClient() as api_client:
# Create an instance of the API class
api_instance = petstore_api.FakeApi(api_client)
param = {'key': 'param_example'} # dict(str, str) | request body
param = {'key': 'param_example'} # dict[str, str] | request body
try:
# test inline additionalProperties
@@ -790,7 +790,7 @@ with petstore_api.ApiClient() as api_client:
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**param** | [**dict(str, str)**](str.md)| request body |
**param** | [**dict[str, str]**](str.md)| request body |
### Return type

View File

@@ -4,10 +4,10 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_map_of_string** | **dict(str, dict(str, str))** | | [optional]
**map_of_enum_string** | **dict(str, str)** | | [optional]
**direct_map** | **dict(str, bool)** | | [optional]
**indirect_map** | **dict(str, bool)** | | [optional]
**map_map_of_string** | **dict[str, dict[str, str]]** | | [optional]
**map_of_enum_string** | **dict[str, str]** | | [optional]
**direct_map** | **dict[str, bool]** | | [optional]
**indirect_map** | **dict[str, bool]** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -6,7 +6,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**uuid** | **str** | | [optional]
**date_time** | **datetime** | | [optional]
**map** | [**dict(str, Animal)**](Animal.md) | | [optional]
**map** | [**dict[str, Animal]**](Animal.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -73,7 +73,7 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **get_inventory**
> dict(str, int) get_inventory()
> dict[str, int] get_inventory()
Returns pet inventories by status
@@ -123,7 +123,7 @@ This endpoint does not need any parameter.
### Return type
**dict(str, int)**
**dict[str, int]**
### Authorization

View File

@@ -1779,7 +1779,7 @@ class FakeApi(object):
>>> result = thread.get()
:param param: request body (required)
:type param: dict(str, str)
:type param: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
@@ -1808,7 +1808,7 @@ class FakeApi(object):
>>> result = thread.get()
:param param: request body (required)
:type param: dict(str, str)
:type param: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code

View File

@@ -190,7 +190,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
kwargs['_return_http_data_only'] = True
return self.get_inventory_with_http_info(**kwargs) # noqa: E501
@@ -226,7 +226,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: tuple(dict(str, int), status_code(int), headers(HTTPHeaderDict))
:rtype: tuple(dict[str, int], status_code(int), headers(HTTPHeaderDict))
"""
local_var_params = locals()
@@ -274,7 +274,7 @@ class StoreApi(object):
auth_settings = ['api_key'] # noqa: E501
response_types_map = {
200: "dict(str, int)",
200: "dict[str, int]",
}
return self.api_client.call_api(

View File

@@ -302,8 +302,8 @@ class ApiClient(object):
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('dict('):
sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
if klass.startswith('dict['):
sub_kls = re.match(r'dict\[([^,]*), (.*)\]', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in six.iteritems(data)}

View File

@@ -36,14 +36,14 @@ class AdditionalPropertiesClass(object):
and the value is json key in definition.
"""
openapi_types = {
'map_string': 'dict(str, str)',
'map_number': 'dict(str, float)',
'map_integer': 'dict(str, int)',
'map_boolean': 'dict(str, bool)',
'map_array_integer': 'dict(str, list[int])',
'map_array_anytype': 'dict(str, list[object])',
'map_map_string': 'dict(str, dict(str, str))',
'map_map_anytype': 'dict(str, dict(str, object))',
'map_string': 'dict[str, str]',
'map_number': 'dict[str, float]',
'map_integer': 'dict[str, int]',
'map_boolean': 'dict[str, bool]',
'map_array_integer': 'dict[str, list[int]]',
'map_array_anytype': 'dict[str, list[object]]',
'map_map_string': 'dict[str, dict[str, str]]',
'map_map_anytype': 'dict[str, dict[str, object]]',
'anytype_1': 'object',
'anytype_2': 'object',
'anytype_3': 'object'
@@ -111,7 +111,7 @@ class AdditionalPropertiesClass(object):
:return: The map_string of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_string
@@ -121,7 +121,7 @@ class AdditionalPropertiesClass(object):
:param map_string: The map_string of this AdditionalPropertiesClass. # noqa: E501
:type map_string: dict(str, str)
:type map_string: dict[str, str]
"""
self._map_string = map_string
@@ -132,7 +132,7 @@ class AdditionalPropertiesClass(object):
:return: The map_number of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, float)
:rtype: dict[str, float]
"""
return self._map_number
@@ -142,7 +142,7 @@ class AdditionalPropertiesClass(object):
:param map_number: The map_number of this AdditionalPropertiesClass. # noqa: E501
:type map_number: dict(str, float)
:type map_number: dict[str, float]
"""
self._map_number = map_number
@@ -153,7 +153,7 @@ class AdditionalPropertiesClass(object):
:return: The map_integer of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
return self._map_integer
@@ -163,7 +163,7 @@ class AdditionalPropertiesClass(object):
:param map_integer: The map_integer of this AdditionalPropertiesClass. # noqa: E501
:type map_integer: dict(str, int)
:type map_integer: dict[str, int]
"""
self._map_integer = map_integer
@@ -174,7 +174,7 @@ class AdditionalPropertiesClass(object):
:return: The map_boolean of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._map_boolean
@@ -184,7 +184,7 @@ class AdditionalPropertiesClass(object):
:param map_boolean: The map_boolean of this AdditionalPropertiesClass. # noqa: E501
:type map_boolean: dict(str, bool)
:type map_boolean: dict[str, bool]
"""
self._map_boolean = map_boolean
@@ -195,7 +195,7 @@ class AdditionalPropertiesClass(object):
:return: The map_array_integer of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, list[int])
:rtype: dict[str, list[int]]
"""
return self._map_array_integer
@@ -205,7 +205,7 @@ class AdditionalPropertiesClass(object):
:param map_array_integer: The map_array_integer of this AdditionalPropertiesClass. # noqa: E501
:type map_array_integer: dict(str, list[int])
:type map_array_integer: dict[str, list[int]]
"""
self._map_array_integer = map_array_integer
@@ -216,7 +216,7 @@ class AdditionalPropertiesClass(object):
:return: The map_array_anytype of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, list[object])
:rtype: dict[str, list[object]]
"""
return self._map_array_anytype
@@ -226,7 +226,7 @@ class AdditionalPropertiesClass(object):
:param map_array_anytype: The map_array_anytype of this AdditionalPropertiesClass. # noqa: E501
:type map_array_anytype: dict(str, list[object])
:type map_array_anytype: dict[str, list[object]]
"""
self._map_array_anytype = map_array_anytype
@@ -237,7 +237,7 @@ class AdditionalPropertiesClass(object):
:return: The map_map_string of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_string
@@ -247,7 +247,7 @@ class AdditionalPropertiesClass(object):
:param map_map_string: The map_map_string of this AdditionalPropertiesClass. # noqa: E501
:type map_map_string: dict(str, dict(str, str))
:type map_map_string: dict[str, dict[str, str]]
"""
self._map_map_string = map_map_string
@@ -258,7 +258,7 @@ class AdditionalPropertiesClass(object):
:return: The map_map_anytype of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, object))
:rtype: dict[str, dict[str, object]]
"""
return self._map_map_anytype
@@ -268,7 +268,7 @@ class AdditionalPropertiesClass(object):
:param map_map_anytype: The map_map_anytype of this AdditionalPropertiesClass. # noqa: E501
:type map_map_anytype: dict(str, dict(str, object))
:type map_map_anytype: dict[str, dict[str, object]]
"""
self._map_map_anytype = map_map_anytype

View File

@@ -36,10 +36,10 @@ class MapTest(object):
and the value is json key in definition.
"""
openapi_types = {
'map_map_of_string': 'dict(str, dict(str, str))',
'map_of_enum_string': 'dict(str, str)',
'direct_map': 'dict(str, bool)',
'indirect_map': 'dict(str, bool)'
'map_map_of_string': 'dict[str, dict[str, str]]',
'map_of_enum_string': 'dict[str, str]',
'direct_map': 'dict[str, bool]',
'indirect_map': 'dict[str, bool]'
}
attribute_map = {
@@ -76,7 +76,7 @@ class MapTest(object):
:return: The map_map_of_string of this MapTest. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_of_string
@@ -86,7 +86,7 @@ class MapTest(object):
:param map_map_of_string: The map_map_of_string of this MapTest. # noqa: E501
:type map_map_of_string: dict(str, dict(str, str))
:type map_map_of_string: dict[str, dict[str, str]]
"""
self._map_map_of_string = map_map_of_string
@@ -97,7 +97,7 @@ class MapTest(object):
:return: The map_of_enum_string of this MapTest. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_of_enum_string
@@ -107,7 +107,7 @@ class MapTest(object):
:param map_of_enum_string: The map_of_enum_string of this MapTest. # noqa: E501
:type map_of_enum_string: dict(str, str)
:type map_of_enum_string: dict[str, str]
"""
allowed_values = ["UPPER", "lower"] # noqa: E501
if (self.local_vars_configuration.client_side_validation and
@@ -126,7 +126,7 @@ class MapTest(object):
:return: The direct_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._direct_map
@@ -136,7 +136,7 @@ class MapTest(object):
:param direct_map: The direct_map of this MapTest. # noqa: E501
:type direct_map: dict(str, bool)
:type direct_map: dict[str, bool]
"""
self._direct_map = direct_map
@@ -147,7 +147,7 @@ class MapTest(object):
:return: The indirect_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._indirect_map
@@ -157,7 +157,7 @@ class MapTest(object):
:param indirect_map: The indirect_map of this MapTest. # noqa: E501
:type indirect_map: dict(str, bool)
:type indirect_map: dict[str, bool]
"""
self._indirect_map = indirect_map

View File

@@ -38,7 +38,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
openapi_types = {
'uuid': 'str',
'date_time': 'datetime',
'map': 'dict(str, Animal)'
'map': 'dict[str, Animal]'
}
attribute_map = {
@@ -113,7 +113,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
:return: The map of this MixedPropertiesAndAdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, Animal)
:rtype: dict[str, Animal]
"""
return self._map
@@ -123,7 +123,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
:param map: The map of this MixedPropertiesAndAdditionalPropertiesClass. # noqa: E501
:type map: dict(str, Animal)
:type map: dict[str, Animal]
"""
self._map = map

View File

@@ -4,14 +4,14 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_string** | **dict(str, str)** | | [optional]
**map_number** | **dict(str, float)** | | [optional]
**map_integer** | **dict(str, int)** | | [optional]
**map_boolean** | **dict(str, bool)** | | [optional]
**map_array_integer** | **dict(str, list[int])** | | [optional]
**map_array_anytype** | **dict(str, list[object])** | | [optional]
**map_map_string** | **dict(str, dict(str, str))** | | [optional]
**map_map_anytype** | **dict(str, dict(str, object))** | | [optional]
**map_string** | **dict[str, str]** | | [optional]
**map_number** | **dict[str, float]** | | [optional]
**map_integer** | **dict[str, int]** | | [optional]
**map_boolean** | **dict[str, bool]** | | [optional]
**map_array_integer** | **dict[str, list[int]]** | | [optional]
**map_array_anytype** | **dict[str, list[object]]** | | [optional]
**map_map_string** | **dict[str, dict[str, str]]** | | [optional]
**map_map_anytype** | **dict[str, dict[str, object]]** | | [optional]
**anytype_1** | **object** | | [optional]
**anytype_2** | **object** | | [optional]
**anytype_3** | **object** | | [optional]

View File

@@ -777,7 +777,7 @@ configuration = petstore_api.Configuration(
with petstore_api.ApiClient() as api_client:
# Create an instance of the API class
api_instance = petstore_api.FakeApi(api_client)
param = {'key': 'param_example'} # dict(str, str) | request body
param = {'key': 'param_example'} # dict[str, str] | request body
try:
# test inline additionalProperties
@@ -790,7 +790,7 @@ with petstore_api.ApiClient() as api_client:
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**param** | [**dict(str, str)**](str.md)| request body |
**param** | [**dict[str, str]**](str.md)| request body |
### Return type

View File

@@ -4,10 +4,10 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_map_of_string** | **dict(str, dict(str, str))** | | [optional]
**map_of_enum_string** | **dict(str, str)** | | [optional]
**direct_map** | **dict(str, bool)** | | [optional]
**indirect_map** | **dict(str, bool)** | | [optional]
**map_map_of_string** | **dict[str, dict[str, str]]** | | [optional]
**map_of_enum_string** | **dict[str, str]** | | [optional]
**direct_map** | **dict[str, bool]** | | [optional]
**indirect_map** | **dict[str, bool]** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -6,7 +6,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**uuid** | **str** | | [optional]
**date_time** | **datetime** | | [optional]
**map** | [**dict(str, Animal)**](Animal.md) | | [optional]
**map** | [**dict[str, Animal]**](Animal.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -73,7 +73,7 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **get_inventory**
> dict(str, int) get_inventory()
> dict[str, int] get_inventory()
Returns pet inventories by status
@@ -123,7 +123,7 @@ This endpoint does not need any parameter.
### Return type
**dict(str, int)**
**dict[str, int]**
### Authorization

View File

@@ -1779,7 +1779,7 @@ class FakeApi(object):
>>> result = thread.get()
:param param: request body (required)
:type param: dict(str, str)
:type param: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
@@ -1808,7 +1808,7 @@ class FakeApi(object):
>>> result = thread.get()
:param param: request body (required)
:type param: dict(str, str)
:type param: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code

View File

@@ -190,7 +190,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
kwargs['_return_http_data_only'] = True
return self.get_inventory_with_http_info(**kwargs) # noqa: E501
@@ -226,7 +226,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: tuple(dict(str, int), status_code(int), headers(HTTPHeaderDict))
:rtype: tuple(dict[str, int], status_code(int), headers(HTTPHeaderDict))
"""
local_var_params = locals()
@@ -274,7 +274,7 @@ class StoreApi(object):
auth_settings = ['api_key'] # noqa: E501
response_types_map = {
200: "dict(str, int)",
200: "dict[str, int]",
}
return self.api_client.call_api(

View File

@@ -301,8 +301,8 @@ class ApiClient(object):
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('dict('):
sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
if klass.startswith('dict['):
sub_kls = re.match(r'dict\[([^,]*), (.*)\]', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in six.iteritems(data)}

View File

@@ -36,14 +36,14 @@ class AdditionalPropertiesClass(object):
and the value is json key in definition.
"""
openapi_types = {
'map_string': 'dict(str, str)',
'map_number': 'dict(str, float)',
'map_integer': 'dict(str, int)',
'map_boolean': 'dict(str, bool)',
'map_array_integer': 'dict(str, list[int])',
'map_array_anytype': 'dict(str, list[object])',
'map_map_string': 'dict(str, dict(str, str))',
'map_map_anytype': 'dict(str, dict(str, object))',
'map_string': 'dict[str, str]',
'map_number': 'dict[str, float]',
'map_integer': 'dict[str, int]',
'map_boolean': 'dict[str, bool]',
'map_array_integer': 'dict[str, list[int]]',
'map_array_anytype': 'dict[str, list[object]]',
'map_map_string': 'dict[str, dict[str, str]]',
'map_map_anytype': 'dict[str, dict[str, object]]',
'anytype_1': 'object',
'anytype_2': 'object',
'anytype_3': 'object'
@@ -111,7 +111,7 @@ class AdditionalPropertiesClass(object):
:return: The map_string of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_string
@@ -121,7 +121,7 @@ class AdditionalPropertiesClass(object):
:param map_string: The map_string of this AdditionalPropertiesClass. # noqa: E501
:type map_string: dict(str, str)
:type map_string: dict[str, str]
"""
self._map_string = map_string
@@ -132,7 +132,7 @@ class AdditionalPropertiesClass(object):
:return: The map_number of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, float)
:rtype: dict[str, float]
"""
return self._map_number
@@ -142,7 +142,7 @@ class AdditionalPropertiesClass(object):
:param map_number: The map_number of this AdditionalPropertiesClass. # noqa: E501
:type map_number: dict(str, float)
:type map_number: dict[str, float]
"""
self._map_number = map_number
@@ -153,7 +153,7 @@ class AdditionalPropertiesClass(object):
:return: The map_integer of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
return self._map_integer
@@ -163,7 +163,7 @@ class AdditionalPropertiesClass(object):
:param map_integer: The map_integer of this AdditionalPropertiesClass. # noqa: E501
:type map_integer: dict(str, int)
:type map_integer: dict[str, int]
"""
self._map_integer = map_integer
@@ -174,7 +174,7 @@ class AdditionalPropertiesClass(object):
:return: The map_boolean of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._map_boolean
@@ -184,7 +184,7 @@ class AdditionalPropertiesClass(object):
:param map_boolean: The map_boolean of this AdditionalPropertiesClass. # noqa: E501
:type map_boolean: dict(str, bool)
:type map_boolean: dict[str, bool]
"""
self._map_boolean = map_boolean
@@ -195,7 +195,7 @@ class AdditionalPropertiesClass(object):
:return: The map_array_integer of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, list[int])
:rtype: dict[str, list[int]]
"""
return self._map_array_integer
@@ -205,7 +205,7 @@ class AdditionalPropertiesClass(object):
:param map_array_integer: The map_array_integer of this AdditionalPropertiesClass. # noqa: E501
:type map_array_integer: dict(str, list[int])
:type map_array_integer: dict[str, list[int]]
"""
self._map_array_integer = map_array_integer
@@ -216,7 +216,7 @@ class AdditionalPropertiesClass(object):
:return: The map_array_anytype of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, list[object])
:rtype: dict[str, list[object]]
"""
return self._map_array_anytype
@@ -226,7 +226,7 @@ class AdditionalPropertiesClass(object):
:param map_array_anytype: The map_array_anytype of this AdditionalPropertiesClass. # noqa: E501
:type map_array_anytype: dict(str, list[object])
:type map_array_anytype: dict[str, list[object]]
"""
self._map_array_anytype = map_array_anytype
@@ -237,7 +237,7 @@ class AdditionalPropertiesClass(object):
:return: The map_map_string of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_string
@@ -247,7 +247,7 @@ class AdditionalPropertiesClass(object):
:param map_map_string: The map_map_string of this AdditionalPropertiesClass. # noqa: E501
:type map_map_string: dict(str, dict(str, str))
:type map_map_string: dict[str, dict[str, str]]
"""
self._map_map_string = map_map_string
@@ -258,7 +258,7 @@ class AdditionalPropertiesClass(object):
:return: The map_map_anytype of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, object))
:rtype: dict[str, dict[str, object]]
"""
return self._map_map_anytype
@@ -268,7 +268,7 @@ class AdditionalPropertiesClass(object):
:param map_map_anytype: The map_map_anytype of this AdditionalPropertiesClass. # noqa: E501
:type map_map_anytype: dict(str, dict(str, object))
:type map_map_anytype: dict[str, dict[str, object]]
"""
self._map_map_anytype = map_map_anytype

View File

@@ -36,10 +36,10 @@ class MapTest(object):
and the value is json key in definition.
"""
openapi_types = {
'map_map_of_string': 'dict(str, dict(str, str))',
'map_of_enum_string': 'dict(str, str)',
'direct_map': 'dict(str, bool)',
'indirect_map': 'dict(str, bool)'
'map_map_of_string': 'dict[str, dict[str, str]]',
'map_of_enum_string': 'dict[str, str]',
'direct_map': 'dict[str, bool]',
'indirect_map': 'dict[str, bool]'
}
attribute_map = {
@@ -76,7 +76,7 @@ class MapTest(object):
:return: The map_map_of_string of this MapTest. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_of_string
@@ -86,7 +86,7 @@ class MapTest(object):
:param map_map_of_string: The map_map_of_string of this MapTest. # noqa: E501
:type map_map_of_string: dict(str, dict(str, str))
:type map_map_of_string: dict[str, dict[str, str]]
"""
self._map_map_of_string = map_map_of_string
@@ -97,7 +97,7 @@ class MapTest(object):
:return: The map_of_enum_string of this MapTest. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_of_enum_string
@@ -107,7 +107,7 @@ class MapTest(object):
:param map_of_enum_string: The map_of_enum_string of this MapTest. # noqa: E501
:type map_of_enum_string: dict(str, str)
:type map_of_enum_string: dict[str, str]
"""
allowed_values = ["UPPER", "lower"] # noqa: E501
if (self.local_vars_configuration.client_side_validation and
@@ -126,7 +126,7 @@ class MapTest(object):
:return: The direct_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._direct_map
@@ -136,7 +136,7 @@ class MapTest(object):
:param direct_map: The direct_map of this MapTest. # noqa: E501
:type direct_map: dict(str, bool)
:type direct_map: dict[str, bool]
"""
self._direct_map = direct_map
@@ -147,7 +147,7 @@ class MapTest(object):
:return: The indirect_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._indirect_map
@@ -157,7 +157,7 @@ class MapTest(object):
:param indirect_map: The indirect_map of this MapTest. # noqa: E501
:type indirect_map: dict(str, bool)
:type indirect_map: dict[str, bool]
"""
self._indirect_map = indirect_map

View File

@@ -38,7 +38,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
openapi_types = {
'uuid': 'str',
'date_time': 'datetime',
'map': 'dict(str, Animal)'
'map': 'dict[str, Animal]'
}
attribute_map = {
@@ -113,7 +113,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
:return: The map of this MixedPropertiesAndAdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, Animal)
:rtype: dict[str, Animal]
"""
return self._map
@@ -123,7 +123,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
:param map: The map of this MixedPropertiesAndAdditionalPropertiesClass. # noqa: E501
:type map: dict(str, Animal)
:type map: dict[str, Animal]
"""
self._map = map

View File

@@ -40,7 +40,7 @@ class DeserializationTests(unittest.TestCase):
}
response = MockResponse(data=json.dumps(data))
deserialized = self.deserialize(response, 'dict(str, EnumTest)')
deserialized = self.deserialize(response, 'dict[str, EnumTest]')
self.assertTrue(isinstance(deserialized, dict))
self.assertTrue(isinstance(deserialized['enum_test'], petstore_api.EnumTest))
self.assertEqual(deserialized['enum_test'],
@@ -74,7 +74,7 @@ class DeserializationTests(unittest.TestCase):
}
response = MockResponse(data=json.dumps(data))
deserialized = self.deserialize(response, 'dict(str, Pet)')
deserialized = self.deserialize(response, 'dict[str, Pet]')
self.assertTrue(isinstance(deserialized, dict))
self.assertTrue(isinstance(deserialized['pet'], petstore_api.Pet))
@@ -90,7 +90,7 @@ class DeserializationTests(unittest.TestCase):
}
response = MockResponse(data=json.dumps(data))
deserialized = self.deserialize(response, 'dict(str, Animal)')
deserialized = self.deserialize(response, 'dict[str, Animal]')
self.assertTrue(isinstance(deserialized, dict))
self.assertTrue(isinstance(deserialized['dog'], petstore_api.Dog))
@@ -101,7 +101,7 @@ class DeserializationTests(unittest.TestCase):
}
response = MockResponse(data=json.dumps(data))
deserialized = self.deserialize(response, 'dict(str, int)')
deserialized = self.deserialize(response, 'dict[str, int]')
self.assertTrue(isinstance(deserialized, dict))
self.assertTrue(isinstance(deserialized['integer'], int))
@@ -218,7 +218,7 @@ class DeserializationTests(unittest.TestCase):
}
response = MockResponse(data=json.dumps(data))
deserialized = self.deserialize(response, "dict(str, dict(str, int))")
deserialized = self.deserialize(response, "dict[str, dict[str, int]]")
self.assertTrue(isinstance(deserialized, dict))
self.assertTrue(isinstance(deserialized["foo"], dict))
self.assertTrue(isinstance(deserialized["foo"]["bar"], int))

View File

@@ -4,14 +4,14 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_string** | **dict(str, str)** | | [optional]
**map_number** | **dict(str, float)** | | [optional]
**map_integer** | **dict(str, int)** | | [optional]
**map_boolean** | **dict(str, bool)** | | [optional]
**map_array_integer** | **dict(str, list[int])** | | [optional]
**map_array_anytype** | **dict(str, list[object])** | | [optional]
**map_map_string** | **dict(str, dict(str, str))** | | [optional]
**map_map_anytype** | **dict(str, dict(str, object))** | | [optional]
**map_string** | **dict[str, str]** | | [optional]
**map_number** | **dict[str, float]** | | [optional]
**map_integer** | **dict[str, int]** | | [optional]
**map_boolean** | **dict[str, bool]** | | [optional]
**map_array_integer** | **dict[str, list[int]]** | | [optional]
**map_array_anytype** | **dict[str, list[object]]** | | [optional]
**map_map_string** | **dict[str, dict[str, str]]** | | [optional]
**map_map_anytype** | **dict[str, dict[str, object]]** | | [optional]
**anytype_1** | **object** | | [optional]
**anytype_2** | **object** | | [optional]
**anytype_3** | **object** | | [optional]

View File

@@ -777,7 +777,7 @@ configuration = petstore_api.Configuration(
with petstore_api.ApiClient() as api_client:
# Create an instance of the API class
api_instance = petstore_api.FakeApi(api_client)
param = {'key': 'param_example'} # dict(str, str) | request body
param = {'key': 'param_example'} # dict[str, str] | request body
try:
# test inline additionalProperties
@@ -790,7 +790,7 @@ with petstore_api.ApiClient() as api_client:
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**param** | [**dict(str, str)**](str.md)| request body |
**param** | [**dict[str, str]**](str.md)| request body |
### Return type

View File

@@ -4,10 +4,10 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_map_of_string** | **dict(str, dict(str, str))** | | [optional]
**map_of_enum_string** | **dict(str, str)** | | [optional]
**direct_map** | **dict(str, bool)** | | [optional]
**indirect_map** | **dict(str, bool)** | | [optional]
**map_map_of_string** | **dict[str, dict[str, str]]** | | [optional]
**map_of_enum_string** | **dict[str, str]** | | [optional]
**direct_map** | **dict[str, bool]** | | [optional]
**indirect_map** | **dict[str, bool]** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -6,7 +6,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**uuid** | **str** | | [optional]
**date_time** | **datetime** | | [optional]
**map** | [**dict(str, Animal)**](Animal.md) | | [optional]
**map** | [**dict[str, Animal]**](Animal.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -73,7 +73,7 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **get_inventory**
> dict(str, int) get_inventory()
> dict[str, int] get_inventory()
Returns pet inventories by status
@@ -123,7 +123,7 @@ This endpoint does not need any parameter.
### Return type
**dict(str, int)**
**dict[str, int]**
### Authorization

View File

@@ -1779,7 +1779,7 @@ class FakeApi(object):
>>> result = thread.get()
:param param: request body (required)
:type param: dict(str, str)
:type param: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
@@ -1808,7 +1808,7 @@ class FakeApi(object):
>>> result = thread.get()
:param param: request body (required)
:type param: dict(str, str)
:type param: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code

View File

@@ -190,7 +190,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
kwargs['_return_http_data_only'] = True
return self.get_inventory_with_http_info(**kwargs) # noqa: E501
@@ -226,7 +226,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: tuple(dict(str, int), status_code(int), headers(HTTPHeaderDict))
:rtype: tuple(dict[str, int], status_code(int), headers(HTTPHeaderDict))
"""
local_var_params = locals()
@@ -274,7 +274,7 @@ class StoreApi(object):
auth_settings = ['api_key'] # noqa: E501
response_types_map = {
200: "dict(str, int)",
200: "dict[str, int]",
}
return self.api_client.call_api(

View File

@@ -303,8 +303,8 @@ class ApiClient(object):
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('dict('):
sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
if klass.startswith('dict['):
sub_kls = re.match(r'dict\[([^,]*), (.*)\]', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in six.iteritems(data)}

View File

@@ -36,14 +36,14 @@ class AdditionalPropertiesClass(object):
and the value is json key in definition.
"""
openapi_types = {
'map_string': 'dict(str, str)',
'map_number': 'dict(str, float)',
'map_integer': 'dict(str, int)',
'map_boolean': 'dict(str, bool)',
'map_array_integer': 'dict(str, list[int])',
'map_array_anytype': 'dict(str, list[object])',
'map_map_string': 'dict(str, dict(str, str))',
'map_map_anytype': 'dict(str, dict(str, object))',
'map_string': 'dict[str, str]',
'map_number': 'dict[str, float]',
'map_integer': 'dict[str, int]',
'map_boolean': 'dict[str, bool]',
'map_array_integer': 'dict[str, list[int]]',
'map_array_anytype': 'dict[str, list[object]]',
'map_map_string': 'dict[str, dict[str, str]]',
'map_map_anytype': 'dict[str, dict[str, object]]',
'anytype_1': 'object',
'anytype_2': 'object',
'anytype_3': 'object'
@@ -111,7 +111,7 @@ class AdditionalPropertiesClass(object):
:return: The map_string of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_string
@@ -121,7 +121,7 @@ class AdditionalPropertiesClass(object):
:param map_string: The map_string of this AdditionalPropertiesClass. # noqa: E501
:type map_string: dict(str, str)
:type map_string: dict[str, str]
"""
self._map_string = map_string
@@ -132,7 +132,7 @@ class AdditionalPropertiesClass(object):
:return: The map_number of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, float)
:rtype: dict[str, float]
"""
return self._map_number
@@ -142,7 +142,7 @@ class AdditionalPropertiesClass(object):
:param map_number: The map_number of this AdditionalPropertiesClass. # noqa: E501
:type map_number: dict(str, float)
:type map_number: dict[str, float]
"""
self._map_number = map_number
@@ -153,7 +153,7 @@ class AdditionalPropertiesClass(object):
:return: The map_integer of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
return self._map_integer
@@ -163,7 +163,7 @@ class AdditionalPropertiesClass(object):
:param map_integer: The map_integer of this AdditionalPropertiesClass. # noqa: E501
:type map_integer: dict(str, int)
:type map_integer: dict[str, int]
"""
self._map_integer = map_integer
@@ -174,7 +174,7 @@ class AdditionalPropertiesClass(object):
:return: The map_boolean of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._map_boolean
@@ -184,7 +184,7 @@ class AdditionalPropertiesClass(object):
:param map_boolean: The map_boolean of this AdditionalPropertiesClass. # noqa: E501
:type map_boolean: dict(str, bool)
:type map_boolean: dict[str, bool]
"""
self._map_boolean = map_boolean
@@ -195,7 +195,7 @@ class AdditionalPropertiesClass(object):
:return: The map_array_integer of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, list[int])
:rtype: dict[str, list[int]]
"""
return self._map_array_integer
@@ -205,7 +205,7 @@ class AdditionalPropertiesClass(object):
:param map_array_integer: The map_array_integer of this AdditionalPropertiesClass. # noqa: E501
:type map_array_integer: dict(str, list[int])
:type map_array_integer: dict[str, list[int]]
"""
self._map_array_integer = map_array_integer
@@ -216,7 +216,7 @@ class AdditionalPropertiesClass(object):
:return: The map_array_anytype of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, list[object])
:rtype: dict[str, list[object]]
"""
return self._map_array_anytype
@@ -226,7 +226,7 @@ class AdditionalPropertiesClass(object):
:param map_array_anytype: The map_array_anytype of this AdditionalPropertiesClass. # noqa: E501
:type map_array_anytype: dict(str, list[object])
:type map_array_anytype: dict[str, list[object]]
"""
self._map_array_anytype = map_array_anytype
@@ -237,7 +237,7 @@ class AdditionalPropertiesClass(object):
:return: The map_map_string of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_string
@@ -247,7 +247,7 @@ class AdditionalPropertiesClass(object):
:param map_map_string: The map_map_string of this AdditionalPropertiesClass. # noqa: E501
:type map_map_string: dict(str, dict(str, str))
:type map_map_string: dict[str, dict[str, str]]
"""
self._map_map_string = map_map_string
@@ -258,7 +258,7 @@ class AdditionalPropertiesClass(object):
:return: The map_map_anytype of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, object))
:rtype: dict[str, dict[str, object]]
"""
return self._map_map_anytype
@@ -268,7 +268,7 @@ class AdditionalPropertiesClass(object):
:param map_map_anytype: The map_map_anytype of this AdditionalPropertiesClass. # noqa: E501
:type map_map_anytype: dict(str, dict(str, object))
:type map_map_anytype: dict[str, dict[str, object]]
"""
self._map_map_anytype = map_map_anytype

View File

@@ -36,10 +36,10 @@ class MapTest(object):
and the value is json key in definition.
"""
openapi_types = {
'map_map_of_string': 'dict(str, dict(str, str))',
'map_of_enum_string': 'dict(str, str)',
'direct_map': 'dict(str, bool)',
'indirect_map': 'dict(str, bool)'
'map_map_of_string': 'dict[str, dict[str, str]]',
'map_of_enum_string': 'dict[str, str]',
'direct_map': 'dict[str, bool]',
'indirect_map': 'dict[str, bool]'
}
attribute_map = {
@@ -76,7 +76,7 @@ class MapTest(object):
:return: The map_map_of_string of this MapTest. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_of_string
@@ -86,7 +86,7 @@ class MapTest(object):
:param map_map_of_string: The map_map_of_string of this MapTest. # noqa: E501
:type map_map_of_string: dict(str, dict(str, str))
:type map_map_of_string: dict[str, dict[str, str]]
"""
self._map_map_of_string = map_map_of_string
@@ -97,7 +97,7 @@ class MapTest(object):
:return: The map_of_enum_string of this MapTest. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_of_enum_string
@@ -107,7 +107,7 @@ class MapTest(object):
:param map_of_enum_string: The map_of_enum_string of this MapTest. # noqa: E501
:type map_of_enum_string: dict(str, str)
:type map_of_enum_string: dict[str, str]
"""
allowed_values = ["UPPER", "lower"] # noqa: E501
if (self.local_vars_configuration.client_side_validation and
@@ -126,7 +126,7 @@ class MapTest(object):
:return: The direct_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._direct_map
@@ -136,7 +136,7 @@ class MapTest(object):
:param direct_map: The direct_map of this MapTest. # noqa: E501
:type direct_map: dict(str, bool)
:type direct_map: dict[str, bool]
"""
self._direct_map = direct_map
@@ -147,7 +147,7 @@ class MapTest(object):
:return: The indirect_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._indirect_map
@@ -157,7 +157,7 @@ class MapTest(object):
:param indirect_map: The indirect_map of this MapTest. # noqa: E501
:type indirect_map: dict(str, bool)
:type indirect_map: dict[str, bool]
"""
self._indirect_map = indirect_map

View File

@@ -38,7 +38,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
openapi_types = {
'uuid': 'str',
'date_time': 'datetime',
'map': 'dict(str, Animal)'
'map': 'dict[str, Animal]'
}
attribute_map = {
@@ -113,7 +113,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
:return: The map of this MixedPropertiesAndAdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, Animal)
:rtype: dict[str, Animal]
"""
return self._map
@@ -123,7 +123,7 @@ class MixedPropertiesAndAdditionalPropertiesClass(object):
:param map: The map of this MixedPropertiesAndAdditionalPropertiesClass. # noqa: E501
:type map: dict(str, Animal)
:type map: dict[str, Animal]
"""
self._map = map

View File

@@ -4,8 +4,8 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_property** | **dict(str, str)** | | [optional]
**map_of_map_property** | **dict(str, dict(str, str))** | | [optional]
**map_property** | **dict[str, str]** | | [optional]
**map_of_map_property** | **dict[str, dict[str, str]]** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -1037,7 +1037,7 @@ configuration = petstore_api.Configuration(
with petstore_api.ApiClient() as api_client:
# Create an instance of the API class
api_instance = petstore_api.FakeApi(api_client)
request_body = {'key': 'request_body_example'} # dict(str, str) | request body
request_body = {'key': 'request_body_example'} # dict[str, str] | request body
try:
# test inline additionalProperties
@@ -1050,7 +1050,7 @@ with petstore_api.ApiClient() as api_client:
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**request_body** | [**dict(str, str)**](str.md)| request body |
**request_body** | [**dict[str, str]**](str.md)| request body |
### Return type
@@ -1167,7 +1167,7 @@ http = ['http_example'] # list[str] |
url = ['url_example'] # list[str] |
context = ['context_example'] # list[str] |
allow_empty = 'allow_empty_example' # str |
language = {'key': 'language_example'} # dict(str, str) | (optional)
language = {'key': 'language_example'} # dict[str, str] | (optional)
try:
api_instance.test_query_parameter_collection_format(pipe, ioutil, http, url, context, allow_empty, language=language)
@@ -1185,7 +1185,7 @@ Name | Type | Description | Notes
**url** | [**list[str]**](str.md)| |
**context** | [**list[str]**](str.md)| |
**allow_empty** | **str**| |
**language** | [**dict(str, str)**](str.md)| | [optional]
**language** | [**dict[str, str]**](str.md)| | [optional]
### Return type

View File

@@ -4,10 +4,10 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**map_map_of_string** | **dict(str, dict(str, str))** | | [optional]
**map_of_enum_string** | **dict(str, str)** | | [optional]
**direct_map** | **dict(str, bool)** | | [optional]
**indirect_map** | **dict(str, bool)** | | [optional]
**map_map_of_string** | **dict[str, dict[str, str]]** | | [optional]
**map_of_enum_string** | **dict[str, str]** | | [optional]
**direct_map** | **dict[str, bool]** | | [optional]
**indirect_map** | **dict[str, bool]** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -6,7 +6,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**uuid** | **str** | | [optional]
**date_time** | **datetime** | | [optional]
**map** | [**dict(str, Animal)**](Animal.md) | | [optional]
**map** | [**dict[str, Animal]**](Animal.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -13,9 +13,9 @@ Name | Type | Description | Notes
**array_nullable_prop** | **list[object]** | | [optional]
**array_and_items_nullable_prop** | **list[object]** | | [optional]
**array_items_nullable** | **list[object]** | | [optional]
**object_nullable_prop** | **dict(str, object)** | | [optional]
**object_and_items_nullable_prop** | **dict(str, object)** | | [optional]
**object_items_nullable** | **dict(str, object)** | | [optional]
**object_nullable_prop** | **dict[str, object]** | | [optional]
**object_and_items_nullable_prop** | **dict[str, object]** | | [optional]
**object_items_nullable** | **dict[str, object]** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -73,7 +73,7 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **get_inventory**
> dict(str, int) get_inventory()
> dict[str, int] get_inventory()
Returns pet inventories by status
@@ -123,7 +123,7 @@ This endpoint does not need any parameter.
### Return type
**dict(str, int)**
**dict[str, int]**
### Authorization

View File

@@ -2238,7 +2238,7 @@ class FakeApi(object):
>>> result = thread.get()
:param request_body: request body (required)
:type request_body: dict(str, str)
:type request_body: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
@@ -2268,7 +2268,7 @@ class FakeApi(object):
>>> result = thread.get()
:param request_body: request body (required)
:type request_body: dict(str, str)
:type request_body: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code
@@ -2538,7 +2538,7 @@ class FakeApi(object):
:param allow_empty: (required)
:type allow_empty: str
:param language:
:type language: dict(str, str)
:type language: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _preload_content: if False, the urllib3.HTTPResponse object will
@@ -2580,7 +2580,7 @@ class FakeApi(object):
:param allow_empty: (required)
:type allow_empty: str
:param language:
:type language: dict(str, str)
:type language: dict[str, str]
:param async_req: Whether to execute the request asynchronously.
:type async_req: bool, optional
:param _return_http_data_only: response data without head status code

View File

@@ -190,7 +190,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: dict(str, int)
:rtype: dict[str, int]
"""
kwargs['_return_http_data_only'] = True
return self.get_inventory_with_http_info(**kwargs) # noqa: E501
@@ -226,7 +226,7 @@ class StoreApi(object):
:return: Returns the result object.
If the method is called asynchronously,
returns the request thread.
:rtype: tuple(dict(str, int), status_code(int), headers(HTTPHeaderDict))
:rtype: tuple(dict[str, int], status_code(int), headers(HTTPHeaderDict))
"""
local_var_params = locals()
@@ -274,7 +274,7 @@ class StoreApi(object):
auth_settings = ['api_key'] # noqa: E501
response_types_map = {
200: "dict(str, int)",
200: "dict[str, int]",
}
return self.api_client.call_api(

View File

@@ -301,8 +301,8 @@ class ApiClient(object):
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]
if klass.startswith('dict('):
sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
if klass.startswith('dict['):
sub_kls = re.match(r'dict\[([^,]*), (.*)\]', klass).group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in six.iteritems(data)}

View File

@@ -36,8 +36,8 @@ class AdditionalPropertiesClass(object):
and the value is json key in definition.
"""
openapi_types = {
'map_property': 'dict(str, str)',
'map_of_map_property': 'dict(str, dict(str, str))'
'map_property': 'dict[str, str]',
'map_of_map_property': 'dict[str, dict[str, str]]'
}
attribute_map = {
@@ -66,7 +66,7 @@ class AdditionalPropertiesClass(object):
:return: The map_property of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_property
@@ -76,7 +76,7 @@ class AdditionalPropertiesClass(object):
:param map_property: The map_property of this AdditionalPropertiesClass. # noqa: E501
:type map_property: dict(str, str)
:type map_property: dict[str, str]
"""
self._map_property = map_property
@@ -87,7 +87,7 @@ class AdditionalPropertiesClass(object):
:return: The map_of_map_property of this AdditionalPropertiesClass. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_of_map_property
@@ -97,7 +97,7 @@ class AdditionalPropertiesClass(object):
:param map_of_map_property: The map_of_map_property of this AdditionalPropertiesClass. # noqa: E501
:type map_of_map_property: dict(str, dict(str, str))
:type map_of_map_property: dict[str, dict[str, str]]
"""
self._map_of_map_property = map_of_map_property

View File

@@ -36,10 +36,10 @@ class MapTest(object):
and the value is json key in definition.
"""
openapi_types = {
'map_map_of_string': 'dict(str, dict(str, str))',
'map_of_enum_string': 'dict(str, str)',
'direct_map': 'dict(str, bool)',
'indirect_map': 'dict(str, bool)'
'map_map_of_string': 'dict[str, dict[str, str]]',
'map_of_enum_string': 'dict[str, str]',
'direct_map': 'dict[str, bool]',
'indirect_map': 'dict[str, bool]'
}
attribute_map = {
@@ -76,7 +76,7 @@ class MapTest(object):
:return: The map_map_of_string of this MapTest. # noqa: E501
:rtype: dict(str, dict(str, str))
:rtype: dict[str, dict[str, str]]
"""
return self._map_map_of_string
@@ -86,7 +86,7 @@ class MapTest(object):
:param map_map_of_string: The map_map_of_string of this MapTest. # noqa: E501
:type map_map_of_string: dict(str, dict(str, str))
:type map_map_of_string: dict[str, dict[str, str]]
"""
self._map_map_of_string = map_map_of_string
@@ -97,7 +97,7 @@ class MapTest(object):
:return: The map_of_enum_string of this MapTest. # noqa: E501
:rtype: dict(str, str)
:rtype: dict[str, str]
"""
return self._map_of_enum_string
@@ -107,7 +107,7 @@ class MapTest(object):
:param map_of_enum_string: The map_of_enum_string of this MapTest. # noqa: E501
:type map_of_enum_string: dict(str, str)
:type map_of_enum_string: dict[str, str]
"""
allowed_values = ["UPPER", "lower"] # noqa: E501
if (self.local_vars_configuration.client_side_validation and
@@ -126,7 +126,7 @@ class MapTest(object):
:return: The direct_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._direct_map
@@ -136,7 +136,7 @@ class MapTest(object):
:param direct_map: The direct_map of this MapTest. # noqa: E501
:type direct_map: dict(str, bool)
:type direct_map: dict[str, bool]
"""
self._direct_map = direct_map
@@ -147,7 +147,7 @@ class MapTest(object):
:return: The indirect_map of this MapTest. # noqa: E501
:rtype: dict(str, bool)
:rtype: dict[str, bool]
"""
return self._indirect_map
@@ -157,7 +157,7 @@ class MapTest(object):
:param indirect_map: The indirect_map of this MapTest. # noqa: E501
:type indirect_map: dict(str, bool)
:type indirect_map: dict[str, bool]
"""
self._indirect_map = indirect_map

Some files were not shown because too many files have changed in this diff Show More