Adds inline composition examples to python-experimental (#11420)

* Adds component with composition in property example

* Adds endpoint parameter examples

* Adds request body examples

* Adds inpline composition example in response body

* Fixes UNKNOWNBASETYPE import bug

* Updates allof inline schemas to be type object with minProperties

* Removes newline

* Adds test_ObjectWithInlineCompositionProperty

* Updates inline schema to be type string, adds partial test_inline_composition

* Fixes accept_content_types input value

* Adds test_ObjectWithInlineCompositionProperty, adds test_inline_composition and starts deserialization of multipart

* Fixes test_inline_composition, adds simple multipat/form-data deserialization
This commit is contained in:
Justin Black 2022-02-03 10:27:52 -06:00 committed by GitHub
parent dc1df25f29
commit 4d9a500c95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1370 additions and 5 deletions

View File

@ -919,6 +919,7 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen {
* With this customization, we ensure that when schemas are passed to getSchemaType
* - if they have ref in them they are a model
* - if they do not have ref in them they are not a model
* and code is also customized to allow anyType request body schemas
*
* @param codegenParameter the body parameter
* @param name model schema ref key in components
@ -936,7 +937,75 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen {
forceSimpleRef = true;
}
}
super.addBodyModelSchema(codegenParameter, name, schema, imports, bodyParameterName, forceSimpleRef);
CodegenModel codegenModel = null;
if (StringUtils.isNotBlank(name)) {
schema.setName(name);
codegenModel = fromModel(name, schema);
}
if (codegenModel != null) {
codegenParameter.isModel = true;
}
if (codegenModel != null && (codegenModel.hasVars || forceSimpleRef)) {
if (StringUtils.isEmpty(bodyParameterName)) {
codegenParameter.baseName = codegenModel.classname;
} else {
codegenParameter.baseName = bodyParameterName;
}
codegenParameter.paramName = toParamName(codegenParameter.baseName);
codegenParameter.baseType = codegenModel.classname;
codegenParameter.dataType = getTypeDeclaration(codegenModel.classname);
codegenParameter.description = codegenModel.description;
codegenParameter.isNullable = codegenModel.isNullable;
imports.add(codegenParameter.baseType);
} else {
CodegenProperty codegenProperty = fromProperty("property", schema);
if (codegenProperty != null && codegenProperty.getComplexType() != null && codegenProperty.getComplexType().contains(" | ")) {
List<String> parts = Arrays.asList(codegenProperty.getComplexType().split(" \\| "));
imports.addAll(parts);
String codegenModelName = codegenProperty.getComplexType();
codegenParameter.baseName = codegenModelName;
codegenParameter.paramName = toParamName(codegenParameter.baseName);
codegenParameter.baseType = codegenParameter.baseName;
codegenParameter.dataType = getTypeDeclaration(codegenModelName);
codegenParameter.description = codegenProperty.getDescription();
codegenParameter.isNullable = codegenProperty.isNullable;
} else {
if (ModelUtils.isMapSchema(schema)) {// http body is map
LOGGER.error("Map should be supported. Please report to openapi-generator github repo about the issue.");
} else if (codegenProperty != null) {
String codegenModelName, codegenModelDescription;
if (codegenModel != null) {
codegenModelName = codegenModel.classname;
codegenModelDescription = codegenModel.description;
} else {
codegenModelName = "anyType";
codegenModelDescription = "";
}
if (StringUtils.isEmpty(bodyParameterName)) {
codegenParameter.baseName = codegenModelName;
} else {
codegenParameter.baseName = bodyParameterName;
}
codegenParameter.paramName = toParamName(codegenParameter.baseName);
codegenParameter.baseType = codegenModelName;
codegenParameter.dataType = getTypeDeclaration(codegenModelName);
codegenParameter.description = codegenModelDescription;
if (codegenProperty.complexType != null) {
imports.add(codegenProperty.complexType);
}
}
}
// set nullable
setParameterNullable(codegenParameter, codegenProperty);
}
}

View File

@ -4,6 +4,7 @@
from dataclasses import dataclass
from decimal import Decimal
import enum
import email
import json
import os
import io
@ -777,6 +778,20 @@ class OpenApiResponse:
else:
return response.data
@staticmethod
def __deserialize_multipart_form_data(
response: urllib3.HTTPResponse
) -> typing.Dict[str, typing.Any]:
msg = email.message_from_bytes(response.data)
return {
part.get_param("name", header="Content-Disposition"): part.get_payload(
decode=True
).decode(part.get_content_charset())
if part.get_content_charset()
else part.get_payload()
for part in msg.get_payload()
}
def deserialize(self, response: urllib3.HTTPResponse, configuration: Configuration) -> ApiResponse:
content_type = response.getheader('content-type')
deserialized_body = unset
@ -786,6 +801,9 @@ class OpenApiResponse:
body_data = self.__deserialize_json(response)
elif content_type == 'application/octet-stream':
body_data = self.__deserialize_application_octet_stream(response)
elif content_type.startswith('multipart/form-data'):
body_data = self.__deserialize_multipart_form_data(response)
content_type = 'multipart/form-data'
else:
raise NotImplementedError('Deserialization of {} has not yet been implemented'.format(content_type))
body_schema = self.content[content_type].schema

View File

@ -1436,6 +1436,60 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HealthCheckResult'
/fake/inlineComposition/:
post:
tags:
- fake
summary: testing composed schemas at inline locations
operationId: inlineComposition
parameters:
- name: compositionAtRoot
in: query
schema:
allOf:
- type: string
minLength: 1
- name: compositionInProperty
in: query
schema:
type: object
properties:
someProp:
allOf:
- type: string
minLength: 1
requestBody:
content:
application/json:
schema:
allOf:
- type: string
minLength: 1
multipart/form-data:
schema:
type: object
properties:
someProp:
allOf:
- type: string
minLength: 1
responses:
200:
description: success
content:
application/json:
schema:
allOf:
- type: string
minLength: 1
multipart/form-data:
schema:
type: object
properties:
someProp:
allOf:
- type: string
minLength: 1
servers:
- url: 'http://{server}.swagger.io:{port}/v2'
description: petstore server
@ -2682,3 +2736,10 @@ components:
format: number
cost:
$ref: '#/components/schemas/Money'
ObjectWithInlineCompositionProperty:
type: object
properties:
someProp:
allOf:
- type: string
minLength: 1

View File

@ -41,6 +41,7 @@ docs/ComposedNumber.md
docs/ComposedObject.md
docs/ComposedOneOfDifferentTypes.md
docs/ComposedString.md
docs/CompositionInProperty.md
docs/Currency.md
docs/DanishPig.md
docs/DateTimeTest.md
@ -95,6 +96,7 @@ docs/ObjectInterface.md
docs/ObjectModelWithRefProps.md
docs/ObjectWithDecimalProperties.md
docs/ObjectWithDifficultlyNamedProps.md
docs/ObjectWithInlineCompositionProperty.md
docs/ObjectWithValidations.md
docs/Order.md
docs/ParentPet.md
@ -179,6 +181,7 @@ petstore_api/model/composed_number.py
petstore_api/model/composed_object.py
petstore_api/model/composed_one_of_different_types.py
petstore_api/model/composed_string.py
petstore_api/model/composition_in_property.py
petstore_api/model/currency.py
petstore_api/model/danish_pig.py
petstore_api/model/date_time_test.py
@ -230,6 +233,7 @@ petstore_api/model/object_interface.py
petstore_api/model/object_model_with_ref_props.py
petstore_api/model/object_with_decimal_properties.py
petstore_api/model/object_with_difficultly_named_props.py
petstore_api/model/object_with_inline_composition_property.py
petstore_api/model/object_with_validations.py
petstore_api/model/order.py
petstore_api/model/parent_pet.py

View File

@ -98,6 +98,7 @@ Class | Method | HTTP request | Description
*FakeApi* | [**fake_health_get**](docs/FakeApi.md#fake_health_get) | **GET** /fake/health | Health check endpoint
*FakeApi* | [**group_parameters**](docs/FakeApi.md#group_parameters) | **DELETE** /fake | Fake endpoint to test group parameters (optional)
*FakeApi* | [**inline_additional_properties**](docs/FakeApi.md#inline_additional_properties) | **POST** /fake/inline-additionalProperties | test inline additionalProperties
*FakeApi* | [**inline_composition**](docs/FakeApi.md#inline_composition) | **POST** /fake/inlineComposition/ | testing composed schemas at inline locations
*FakeApi* | [**json_form_data**](docs/FakeApi.md#json_form_data) | **GET** /fake/jsonFormData | test json serialization of form data
*FakeApi* | [**mammal**](docs/FakeApi.md#mammal) | **POST** /fake/refs/mammal |
*FakeApi* | [**number_with_validations**](docs/FakeApi.md#number_with_validations) | **POST** /fake/refs/number |
@ -172,6 +173,7 @@ Class | Method | HTTP request | Description
- [ComposedObject](docs/ComposedObject.md)
- [ComposedOneOfDifferentTypes](docs/ComposedOneOfDifferentTypes.md)
- [ComposedString](docs/ComposedString.md)
- [CompositionInProperty](docs/CompositionInProperty.md)
- [Currency](docs/Currency.md)
- [DanishPig](docs/DanishPig.md)
- [DateTimeTest](docs/DateTimeTest.md)
@ -223,6 +225,7 @@ Class | Method | HTTP request | Description
- [ObjectModelWithRefProps](docs/ObjectModelWithRefProps.md)
- [ObjectWithDecimalProperties](docs/ObjectWithDecimalProperties.md)
- [ObjectWithDifficultlyNamedProps](docs/ObjectWithDifficultlyNamedProps.md)
- [ObjectWithInlineCompositionProperty](docs/ObjectWithInlineCompositionProperty.md)
- [ObjectWithValidations](docs/ObjectWithValidations.md)
- [Order](docs/Order.md)
- [ParentPet](docs/ParentPet.md)

View File

@ -0,0 +1,10 @@
# CompositionInProperty
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**someProp** | **object** | | [optional]
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [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

@ -18,6 +18,7 @@ Method | HTTP request | Description
[**fake_health_get**](FakeApi.md#fake_health_get) | **GET** /fake/health | Health check endpoint
[**group_parameters**](FakeApi.md#group_parameters) | **DELETE** /fake | Fake endpoint to test group parameters (optional)
[**inline_additional_properties**](FakeApi.md#inline_additional_properties) | **POST** /fake/inline-additionalProperties | test inline additionalProperties
[**inline_composition**](FakeApi.md#inline_composition) | **POST** /fake/inlineComposition/ | testing composed schemas at inline locations
[**json_form_data**](FakeApi.md#json_form_data) | **GET** /fake/jsonFormData | test json serialization of form data
[**mammal**](FakeApi.md#mammal) | **POST** /fake/refs/mammal |
[**number_with_validations**](FakeApi.md#number_with_validations) | **POST** /fake/refs/number |
@ -1408,6 +1409,136 @@ 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)
# **inline_composition**
> object inline_composition()
testing composed schemas at inline locations
### Example
```python
import petstore_api
from petstore_api.api import fake_api
from petstore_api.model.composition_in_property import CompositionInProperty
from pprint import pprint
# Defining the host is optional and defaults to http://petstore.swagger.io:80/v2
# See configuration.py for a list of all supported configuration parameters.
configuration = petstore_api.Configuration(
host = "http://petstore.swagger.io:80/v2"
)
# Enter a context with an instance of the API client
with petstore_api.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = fake_api.FakeApi(api_client)
# example passing only optional values
query_params = {
'compositionAtRoot': ,
'compositionInProperty': dict(
some_prop=,
),
}
body =
try:
# testing composed schemas at inline locations
api_response = api_instance.inline_composition(
query_params=query_params,
body=body,
)
pprint(api_response)
except petstore_api.ApiException as e:
print("Exception when calling FakeApi->inline_composition: %s\n" % e)
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
body | typing.Union[SchemaForRequestBodyApplicationJson, SchemaForRequestBodyMultipartFormData, Unset] | optional, default is unset |
query_params | RequestQueryParams | |
content_type | str | optional, default is 'application/json' | Selects the schema and serialization of the request body
accept_content_types | typing.Tuple[str] | default is ('application/json', 'multipart/form-data', ) | Tells the server the content type(s) that are accepted by the client
stream | bool | default is False | if True then the response.content will be streamed and loaded from a file like object. When downloading a file, set this to True to force the code to deserialize the content to a FileSchema file
timeout | typing.Optional[typing.Union[int, typing.Tuple]] | default is None | the timeout used by the rest client
skip_deserialization | bool | default is False | when True, headers and body will be unset and an instance of api_client.ApiResponseWithoutDeserialization will be returned
### body
#### SchemaForRequestBodyApplicationJson
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
#### SchemaForRequestBodyMultipartFormData
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**someProp** | **object** | | [optional]
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
### query_params
#### RequestQueryParams
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
compositionAtRoot | CompositionAtRootSchema | | optional
compositionInProperty | CompositionInPropertySchema | | optional
#### CompositionAtRootSchema
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
#### CompositionInPropertySchema
Type | Description | Notes
------------- | ------------- | -------------
[**{str: (bool, date, datetime, dict, float, int, list, str, none_type)}**](CompositionInProperty.md) | |
### Return Types, Responses
Code | Class | Description
------------- | ------------- | -------------
n/a | api_client.ApiResponseWithoutDeserialization | When skip_deserialization is True this response is returned
200 | ApiResponseFor200 | success
#### ApiResponseFor200
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
response | urllib3.HTTPResponse | Raw response |
body | typing.Union[SchemaFor200ResponseBodyApplicationJson, SchemaFor200ResponseBodyMultipartFormData, ] | |
headers | Unset | headers were not defined |
#### SchemaFor200ResponseBodyApplicationJson
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
#### SchemaFor200ResponseBodyMultipartFormData
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**someProp** | **object** | | [optional]
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
**object**
### Authorization
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)
# **json_form_data**
> json_form_data()

View File

@ -0,0 +1,10 @@
# ObjectWithInlineCompositionProperty
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**someProp** | **object** | | [optional]
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [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

@ -24,6 +24,7 @@ from petstore_api.api.fake_api_endpoints.enum_parameters import EnumParameters
from petstore_api.api.fake_api_endpoints.fake_health_get import FakeHealthGet
from petstore_api.api.fake_api_endpoints.group_parameters import GroupParameters
from petstore_api.api.fake_api_endpoints.inline_additional_properties import InlineAdditionalProperties
from petstore_api.api.fake_api_endpoints.inline_composition import InlineComposition
from petstore_api.api.fake_api_endpoints.json_form_data import JsonFormData
from petstore_api.api.fake_api_endpoints.mammal import Mammal
from petstore_api.api.fake_api_endpoints.number_with_validations import NumberWithValidations
@ -52,6 +53,7 @@ class FakeApi(
FakeHealthGet,
GroupParameters,
InlineAdditionalProperties,
InlineComposition,
JsonFormData,
Mammal,
NumberWithValidations,

View File

@ -0,0 +1,554 @@
# coding: utf-8
"""
Generated by: https://openapi-generator.tech
"""
from dataclasses import dataclass
import re # noqa: F401
import sys # noqa: F401
import typing
import urllib3
from urllib3._collections import HTTPHeaderDict
from petstore_api import api_client, exceptions
import decimal # noqa: F401
from datetime import date, datetime # noqa: F401
from frozendict import frozendict # noqa: F401
from petstore_api.schemas import ( # noqa: F401
AnyTypeSchema,
ComposedSchema,
DictSchema,
ListSchema,
StrSchema,
IntSchema,
Int32Schema,
Int64Schema,
Float32Schema,
Float64Schema,
NumberSchema,
DateSchema,
DateTimeSchema,
DecimalSchema,
BoolSchema,
BinarySchema,
NoneSchema,
none_type,
InstantiationMetadata,
Unset,
unset,
ComposedBase,
ListBase,
DictBase,
NoneBase,
StrBase,
IntBase,
NumberBase,
DateBase,
DateTimeBase,
BoolBase,
BinaryBase,
Schema,
_SchemaValidator,
_SchemaTypeChecker,
_SchemaEnumMaker
)
from petstore_api.model.composition_in_property import CompositionInProperty
# query params
class CompositionAtRootSchema(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'CompositionAtRootSchema':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
class CompositionInPropertySchema(
DictSchema
):
class someProp(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'someProp':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
def __new__(
cls,
*args: typing.Union[dict, frozendict, ],
someProp: typing.Union[someProp, Unset] = unset,
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'CompositionInPropertySchema':
return super().__new__(
cls,
*args,
someProp=someProp,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
RequestRequiredQueryParams = typing.TypedDict(
'RequestRequiredQueryParams',
{
}
)
RequestOptionalQueryParams = typing.TypedDict(
'RequestOptionalQueryParams',
{
'compositionAtRoot': CompositionAtRootSchema,
'compositionInProperty': CompositionInPropertySchema,
},
total=False
)
class RequestQueryParams(RequestRequiredQueryParams, RequestOptionalQueryParams):
pass
request_query_composition_at_root = api_client.QueryParameter(
name="compositionAtRoot",
style=api_client.ParameterStyle.FORM,
schema=CompositionAtRootSchema,
explode=True,
)
request_query_composition_in_property = api_client.QueryParameter(
name="compositionInProperty",
style=api_client.ParameterStyle.FORM,
schema=CompositionInPropertySchema,
explode=True,
)
# body param
class SchemaForRequestBodyApplicationJson(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'SchemaForRequestBodyApplicationJson':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
class SchemaForRequestBodyMultipartFormData(
DictSchema
):
class someProp(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'someProp':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
def __new__(
cls,
*args: typing.Union[dict, frozendict, ],
someProp: typing.Union[someProp, Unset] = unset,
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'SchemaForRequestBodyMultipartFormData':
return super().__new__(
cls,
*args,
someProp=someProp,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
request_body_any_type = api_client.RequestBody(
content={
'application/json': api_client.MediaType(
schema=SchemaForRequestBodyApplicationJson),
'multipart/form-data': api_client.MediaType(
schema=SchemaForRequestBodyMultipartFormData),
},
)
_path = '/fake/inlineComposition/'
_method = 'POST'
class SchemaFor200ResponseBodyApplicationJson(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'SchemaFor200ResponseBodyApplicationJson':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
class SchemaFor200ResponseBodyMultipartFormData(
DictSchema
):
class someProp(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'someProp':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
def __new__(
cls,
*args: typing.Union[dict, frozendict, ],
someProp: typing.Union[someProp, Unset] = unset,
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'SchemaFor200ResponseBodyMultipartFormData':
return super().__new__(
cls,
*args,
someProp=someProp,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
@dataclass
class ApiResponseFor200(api_client.ApiResponse):
response: urllib3.HTTPResponse
body: typing.Union[
SchemaFor200ResponseBodyApplicationJson,
SchemaFor200ResponseBodyMultipartFormData,
]
headers: Unset = unset
_response_for_200 = api_client.OpenApiResponse(
response_cls=ApiResponseFor200,
content={
'application/json': api_client.MediaType(
schema=SchemaFor200ResponseBodyApplicationJson),
'multipart/form-data': api_client.MediaType(
schema=SchemaFor200ResponseBodyMultipartFormData),
},
)
_status_code_to_response = {
'200': _response_for_200,
}
_all_accept_content_types = (
'application/json',
'multipart/form-data',
)
class InlineComposition(api_client.Api):
def inline_composition(
self: api_client.Api,
body: typing.Union[SchemaForRequestBodyApplicationJson, SchemaForRequestBodyMultipartFormData, Unset] = unset,
query_params: RequestQueryParams = frozendict(),
content_type: str = 'application/json',
accept_content_types: typing.Tuple[str] = _all_accept_content_types,
stream: bool = False,
timeout: typing.Optional[typing.Union[int, typing.Tuple]] = None,
skip_deserialization: bool = False,
) -> typing.Union[
ApiResponseFor200,
api_client.ApiResponseWithoutDeserialization
]:
"""
testing composed schemas at inline locations
:param skip_deserialization: If true then api_response.response will be set but
api_response.body and api_response.headers will not be deserialized into schema
class instances
"""
self._verify_typed_dict_inputs(RequestQueryParams, query_params)
_query_params = []
for parameter in (
request_query_composition_at_root,
request_query_composition_in_property,
):
parameter_data = query_params.get(parameter.name, unset)
if parameter_data is unset:
continue
serialized_data = parameter.serialize(parameter_data)
_query_params.extend(serialized_data)
_headers = HTTPHeaderDict()
# TODO add cookie handling
if accept_content_types:
for accept_content_type in accept_content_types:
_headers.add('Accept', accept_content_type)
_fields = None
_body = None
if body is not unset:
serialized_data = request_body_any_type.serialize(body, content_type)
_headers.add('Content-Type', content_type)
if 'fields' in serialized_data:
_fields = serialized_data['fields']
elif 'body' in serialized_data:
_body = serialized_data['body']
response = self.api_client.call_api(
resource_path=_path,
method=_method,
query_params=tuple(_query_params),
headers=_headers,
fields=_fields,
body=_body,
stream=stream,
timeout=timeout,
)
if skip_deserialization:
api_response = api_client.ApiResponseWithoutDeserialization(response=response)
else:
response_for_status = _status_code_to_response.get(str(response.status))
if response_for_status:
api_response = response_for_status.deserialize(response, self.api_client.configuration)
else:
api_response = api_client.ApiResponseWithoutDeserialization(response=response)
if not 200 <= response.status <= 299:
raise exceptions.ApiException(api_response=api_response)
return api_response

View File

@ -11,6 +11,7 @@
from dataclasses import dataclass
from decimal import Decimal
import enum
import email
import json
import os
import io
@ -781,6 +782,20 @@ class OpenApiResponse:
else:
return response.data
@staticmethod
def __deserialize_multipart_form_data(
response: urllib3.HTTPResponse
) -> typing.Dict[str, typing.Any]:
msg = email.message_from_bytes(response.data)
return {
part.get_param("name", header="Content-Disposition"): part.get_payload(
decode=True
).decode(part.get_content_charset())
if part.get_content_charset()
else part.get_payload()
for part in msg.get_payload()
}
def deserialize(self, response: urllib3.HTTPResponse, configuration: Configuration) -> ApiResponse:
content_type = response.getheader('content-type')
deserialized_body = unset
@ -790,6 +805,9 @@ class OpenApiResponse:
body_data = self.__deserialize_json(response)
elif content_type == 'application/octet-stream':
body_data = self.__deserialize_application_octet_stream(response)
elif content_type.startswith('multipart/form-data'):
body_data = self.__deserialize_multipart_form_data(response)
content_type = 'multipart/form-data'
else:
raise NotImplementedError('Deserialization of {} has not yet been implemented'.format(content_type))
body_schema = self.content[content_type].schema

View File

@ -0,0 +1,132 @@
# coding: utf-8
"""
OpenAPI Petstore
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
The version of the OpenAPI document: 1.0.0
Generated by: https://openapi-generator.tech
"""
import re # noqa: F401
import sys # noqa: F401
import typing # noqa: F401
from frozendict import frozendict # noqa: F401
import decimal # noqa: F401
from datetime import date, datetime # noqa: F401
from frozendict import frozendict # noqa: F401
from petstore_api.schemas import ( # noqa: F401
AnyTypeSchema,
ComposedSchema,
DictSchema,
ListSchema,
StrSchema,
IntSchema,
Int32Schema,
Int64Schema,
Float32Schema,
Float64Schema,
NumberSchema,
DateSchema,
DateTimeSchema,
DecimalSchema,
BoolSchema,
BinarySchema,
NoneSchema,
none_type,
InstantiationMetadata,
Unset,
unset,
ComposedBase,
ListBase,
DictBase,
NoneBase,
StrBase,
IntBase,
NumberBase,
DateBase,
DateTimeBase,
BoolBase,
BinaryBase,
Schema,
_SchemaValidator,
_SchemaTypeChecker,
_SchemaEnumMaker
)
class CompositionInProperty(
DictSchema
):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
class someProp(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'someProp':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
def __new__(
cls,
*args: typing.Union[dict, frozendict, ],
someProp: typing.Union[someProp, Unset] = unset,
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'CompositionInProperty':
return super().__new__(
cls,
*args,
someProp=someProp,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)

View File

@ -0,0 +1,132 @@
# coding: utf-8
"""
OpenAPI Petstore
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
The version of the OpenAPI document: 1.0.0
Generated by: https://openapi-generator.tech
"""
import re # noqa: F401
import sys # noqa: F401
import typing # noqa: F401
from frozendict import frozendict # noqa: F401
import decimal # noqa: F401
from datetime import date, datetime # noqa: F401
from frozendict import frozendict # noqa: F401
from petstore_api.schemas import ( # noqa: F401
AnyTypeSchema,
ComposedSchema,
DictSchema,
ListSchema,
StrSchema,
IntSchema,
Int32Schema,
Int64Schema,
Float32Schema,
Float64Schema,
NumberSchema,
DateSchema,
DateTimeSchema,
DecimalSchema,
BoolSchema,
BinarySchema,
NoneSchema,
none_type,
InstantiationMetadata,
Unset,
unset,
ComposedBase,
ListBase,
DictBase,
NoneBase,
StrBase,
IntBase,
NumberBase,
DateBase,
DateTimeBase,
BoolBase,
BinaryBase,
Schema,
_SchemaValidator,
_SchemaTypeChecker,
_SchemaEnumMaker
)
class ObjectWithInlineCompositionProperty(
DictSchema
):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
Do not edit the class manually.
"""
class someProp(
ComposedSchema
):
@classmethod
@property
def _composed_schemas(cls):
# we need this here to make our import statements work
# we must store _composed_schemas in here so the code is only run
# when we invoke this method. If we kept this at the class
# level we would get an error because the class level
# code would be run when this module is imported, and these composed
# classes don't exist yet because their module has not finished
# loading
class allOf_0(
_SchemaValidator(
min_length=1,
),
StrSchema
):
pass
return {
'allOf': [
allOf_0,
],
'oneOf': [
],
'anyOf': [
],
}
def __new__(
cls,
*args: typing.Union[dict, frozendict, str, date, datetime, int, float, decimal.Decimal, None, list, tuple, bytes],
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'someProp':
return super().__new__(
cls,
*args,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)
def __new__(
cls,
*args: typing.Union[dict, frozendict, ],
someProp: typing.Union[someProp, Unset] = unset,
_instantiation_metadata: typing.Optional[InstantiationMetadata] = None,
**kwargs: typing.Type[Schema],
) -> 'ObjectWithInlineCompositionProperty':
return super().__new__(
cls,
*args,
someProp=someProp,
_instantiation_metadata=_instantiation_metadata,
**kwargs,
)

View File

@ -49,6 +49,7 @@ from petstore_api.model.composed_number import ComposedNumber
from petstore_api.model.composed_object import ComposedObject
from petstore_api.model.composed_one_of_different_types import ComposedOneOfDifferentTypes
from petstore_api.model.composed_string import ComposedString
from petstore_api.model.composition_in_property import CompositionInProperty
from petstore_api.model.currency import Currency
from petstore_api.model.danish_pig import DanishPig
from petstore_api.model.date_time_test import DateTimeTest
@ -100,6 +101,7 @@ from petstore_api.model.object_interface import ObjectInterface
from petstore_api.model.object_model_with_ref_props import ObjectModelWithRefProps
from petstore_api.model.object_with_decimal_properties import ObjectWithDecimalProperties
from petstore_api.model.object_with_difficultly_named_props import ObjectWithDifficultlyNamedProps
from petstore_api.model.object_with_inline_composition_property import ObjectWithInlineCompositionProperty
from petstore_api.model.object_with_validations import ObjectWithValidations
from petstore_api.model.order import Order
from petstore_api.model.parent_pet import ParentPet

View File

@ -0,0 +1,35 @@
# coding: utf-8
"""
OpenAPI Petstore
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
The version of the OpenAPI document: 1.0.0
Generated by: https://openapi-generator.tech
"""
import unittest
import petstore_api
from petstore_api.model.composition_in_property import CompositionInProperty
class TestCompositionInProperty(unittest.TestCase):
"""CompositionInProperty unit test stubs"""
def setUp(self):
pass
def tearDown(self):
pass
def test_CompositionInProperty(self):
"""Test CompositionInProperty"""
# FIXME: construct object with mandatory attributes with example values
# model = CompositionInProperty() # noqa: E501
pass
if __name__ == '__main__':
unittest.main()

View File

@ -116,6 +116,13 @@ class TestFakeApi(unittest.TestCase):
"""
pass
def test_inline_composition(self):
"""Test case for inline_composition
testing composed schemas at inline locations # noqa: E501
"""
pass
def test_json_form_data(self):
"""Test case for json_form_data

View File

@ -0,0 +1,35 @@
# coding: utf-8
"""
OpenAPI Petstore
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
The version of the OpenAPI document: 1.0.0
Generated by: https://openapi-generator.tech
"""
import unittest
import petstore_api
from petstore_api.model.object_with_inline_composition_property import ObjectWithInlineCompositionProperty
class TestObjectWithInlineCompositionProperty(unittest.TestCase):
"""ObjectWithInlineCompositionProperty unit test stubs"""
def setUp(self):
pass
def tearDown(self):
pass
def test_ObjectWithInlineCompositionProperty(self):
"""Test ObjectWithInlineCompositionProperty"""
# FIXME: construct object with mandatory attributes with example values
# model = ObjectWithInlineCompositionProperty() # noqa: E501
pass
if __name__ == '__main__':
unittest.main()

View File

@ -8,7 +8,8 @@
The version of the OpenAPI document: 1.0.0
Generated by: https://openapi-generator.tech
"""
from email.mime import multipart
from email.mime import nonmultipart
import io
import sys
import unittest
@ -20,11 +21,18 @@ import urllib3
from urllib3._collections import HTTPHeaderDict
import petstore_api
from petstore_api import api_client, schemas
from petstore_api import api_client, schemas, exceptions
from petstore_api.api.fake_api import FakeApi # noqa: E501
from petstore_api.rest import RESTClientObject
class MIMEFormdata(nonmultipart.MIMENonMultipart):
def __init__(self, keyname, *args, **kwargs):
super(MIMEFormdata, self).__init__(*args, **kwargs)
self.add_header(
"Content-Disposition", "form-data; name=\"%s\"" % keyname)
class TestFakeApi(unittest.TestCase):
"""FakeApi unit test stubs"""
json_content_type = 'application/json'
@ -67,6 +75,7 @@ class TestFakeApi(unittest.TestCase):
fields: typing.Optional[tuple[api_client.RequestField, ...]] = None,
accept_content_type: str = 'application/json',
stream: bool = False,
query_params: typing.Optional[typing.Tuple[typing.Tuple[str, str], ...]] = None
):
mock_request.assert_called_with(
'POST',
@ -79,7 +88,7 @@ class TestFakeApi(unittest.TestCase):
}
),
body=body,
query_params=None,
query_params=query_params,
fields=fields,
stream=stream,
timeout=None,
@ -570,6 +579,106 @@ class TestFakeApi(unittest.TestCase):
)
self.assertEqual(api_response.body, response_json)
@staticmethod
def __encode_multipart_formdata(fields: typing.Dict[str, typing.Any]) -> multipart.MIMEMultipart:
m = multipart.MIMEMultipart("form-data")
for field, value in fields.items():
data = MIMEFormdata(field, "text", "plain")
# data.set_payload(value, charset='us-ascii')
data.set_payload(value)
m.attach(data)
return m
@patch.object(RESTClientObject, 'request')
def test_inline_composition(self, mock_request):
"""Test case for inline_composition
testing composed schemas at inline locations # noqa: E501
"""
single_char_str = 'a'
json_bytes = self.__json_bytes(single_char_str)
# tx and rx json with composition at root level of schema for request + response body
content_type = 'application/json'
mock_request.return_value = self.__response(
json_bytes
)
api_response = self.api.inline_composition(
body=single_char_str,
query_params={
'compositionAtRoot': single_char_str,
'compositionInProperty': {'someProp': single_char_str}
},
accept_content_types=(content_type,)
)
self.__assert_request_called_with(
mock_request,
'http://petstore.swagger.io:80/v2/fake/inlineComposition/',
accept_content_type=content_type,
content_type=content_type,
query_params=(('compositionAtRoot', 'a'), ('someProp', 'a')),
body=json_bytes
)
self.assertEqual(api_response.body, single_char_str)
self.assertTrue(isinstance(api_response.body, schemas.StrSchema))
# tx and rx json with composition at property level of schema for request + response body
content_type = 'multipart/form-data'
multipart_response = self.__encode_multipart_formdata(fields={'someProp': single_char_str})
mock_request.return_value = self.__response(
bytes(multipart_response),
content_type=multipart_response.get_content_type()
)
api_response = self.api.inline_composition(
body={'someProp': single_char_str},
query_params={
'compositionAtRoot': single_char_str,
'compositionInProperty': {'someProp': single_char_str}
},
content_type=content_type,
accept_content_types=(content_type,)
)
self.__assert_request_called_with(
mock_request,
'http://petstore.swagger.io:80/v2/fake/inlineComposition/',
accept_content_type=content_type,
content_type=content_type,
query_params=(('compositionAtRoot', 'a'), ('someProp', 'a')),
fields=(
api_client.RequestField(
name='someProp',
data=single_char_str,
headers={'Content-Type': 'text/plain'}
),
),
)
self.assertEqual(api_response.body, {'someProp': single_char_str})
self.assertTrue(isinstance(api_response.body.someProp, schemas.StrSchema))
# error thrown when a str is input which doesn't meet the composed schema length constraint
invalid_value = ''
variable_locations = 4
for invalid_index in range(variable_locations):
values = [single_char_str]*variable_locations
values[invalid_index] = invalid_value
with self.assertRaises(exceptions.ApiValueError):
multipart_response = self.__encode_multipart_formdata(fields={'someProp': values[0]})
mock_request.return_value = self.__response(
bytes(multipart_response),
content_type=multipart_response.get_content_type()
)
self.api.inline_composition(
body={'someProp': values[1]},
query_params={
'compositionAtRoot': values[2],
'compositionInProperty': {'someProp': values[3]}
},
content_type=content_type,
accept_content_types=(content_type,)
)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,33 @@
# coding: utf-8
"""
OpenAPI Petstore
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
The version of the OpenAPI document: 1.0.0
Generated by: https://openapi-generator.tech
"""
import unittest
from petstore_api import schemas, exceptions
from petstore_api.model.object_with_inline_composition_property import ObjectWithInlineCompositionProperty
class TestObjectWithInlineCompositionProperty(unittest.TestCase):
"""ObjectWithInlineCompositionProperty unit test stubs"""
def test_ObjectWithInlineCompositionProperty(self):
"""Test ObjectWithInlineCompositionProperty"""
model = ObjectWithInlineCompositionProperty(someProp='a')
self.assertTrue(isinstance(model.someProp, ObjectWithInlineCompositionProperty.someProp))
self.assertTrue(isinstance(model.someProp, schemas.StrSchema))
# error thrown on length < 1
with self.assertRaises(exceptions.ApiValueError):
ObjectWithInlineCompositionProperty(someProp='')
if __name__ == '__main__':
unittest.main()