Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -726,9 +726,31 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
}

Map<String, ModelsMap> processed = super.postProcessAllModels(objs);
Set<String> composedModels = new HashSet<>();
for (ModelsMap modelsMap : processed.values()) {
for (ModelMap modelMap : modelsMap.getModels()) {
CodegenModel model = modelMap.getModel();
if (model != null && (hasOneOf(model) || hasAnyOf(model))) {
composedModels.add(model.classname);
}
}
}
for (ModelsMap modelsMap : processed.values()) {
for (ModelMap modelMap : modelsMap.getModels()) {
CodegenModel model = modelMap.getModel();
if (model != null && (hasOneOf(model) || hasAnyOf(model))) {
List<CodegenProperty> alternatives = hasOneOf(model)
? model.getComposedSchemas().getOneOf()
: model.getComposedSchemas().getAnyOf();
for (CodegenProperty property : alternatives) {
if (property.isContainer) {
String expression = fromDictExpression(property, "data", 0, composedModels);
if (!expression.equals("data")) {
property.vendorExtensions.put("x-py-from-dict", expression);
}
}
}
}
if (model != null && model.oneOf.isEmpty() && model.anyOf.isEmpty()) {
for (CodegenProperty property : model.vars) {
if (property.vendorExtensions.containsKey(
Expand All @@ -751,6 +773,35 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
return processed;
}

private String fromDictExpression(CodegenProperty property, String value, int depth,
Set<String> composedModels) {
String item = "_item" + depth;
if (property.isContainer && property.items != null) {
String expression = fromDictExpression(property.items, item, depth + 1, composedModels);
if (expression.equals(item)) {
return value;
}
if (property.isArray) {
return "([" + expression
+ " for " + item + " in " + value + "] if isinstance(" + value
+ ", list) else " + value + ")";
}
if (property.isMap) {
String key = "_key" + depth;
return "({" + key + ": " + expression
+ " for " + key + ", " + item + " in " + value + ".items()} if isinstance("
+ value + ", dict) else " + value + ")";
}
}
// Pydantic cannot decode raw values into the generated union wrappers.
// Ordinary models must retain Pydantic's existing defaults/field presence.
if (composedModels.contains(property.dataType)) {
return "(" + property.dataType + ".from_dict(" + value + ") if "
+ value + " is not None else None)";
}
return value;
}

private void configurePublicNameInputs(List<CodegenProperty> properties) {
for (CodegenProperty property : properties) {
String publicName = (String) property.vendorExtensions.getOrDefault(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def _to_dict(value: Any) -> Any:
if isinstance(value, list):
return [_to_dict(item) for item in value]
if isinstance(value, dict):
return {key: _to_dict(item) for key, item in value.items()}
if hasattr(value, "to_dict") and callable(value.to_dict):
return value.to_dict()
return value

Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ import re # noqa: F401
from typing import Union, Any, List, Set, TYPE_CHECKING, Optional, Dict
from typing_extensions import Literal, Self
from pydantic import Field
{{#compatibleWithPythonLegacy}}
from pydantic_core import to_jsonable_python
{{#compatibleWithPythonLegacy}}


{{>_legacy_model_dict_helpers}}

{{/compatibleWithPythonLegacy}}
{{^compatibleWithPythonLegacy}}

{{>_composed_model_dict}}
{{/compatibleWithPythonLegacy}}

{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ANY_OF_SCHEMAS = [{{#anyOf}}"{{.}}"{{^-last}}, {{/-last}}{{/anyOf}}]
Expand Down Expand Up @@ -119,12 +123,16 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{#isContainer}}
# deserialize data into {{{dataType}}}
try:
data = json.loads(json_str)
{{#vendorExtensions.x-py-from-dict}}
data = {{{vendorExtensions.x-py-from-dict}}}
{{/vendorExtensions.x-py-from-dict}}
# validation
instance.{{vendorExtensions.x-py-name}} = json.loads(json_str)
instance.{{vendorExtensions.x-py-name}} = data
# assign value to actual_instance
instance.actual_instance = instance.{{vendorExtensions.x-py-name}}
return instance
except (ValidationError, ValueError) as e:
except (ValidationError, ValueError, TypeError, AttributeError) as e:
error_messages.append(str(e))
{{/isContainer}}
{{^isContainer}}
Expand Down Expand Up @@ -172,7 +180,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{/compatibleWithPythonLegacy}}
{{^compatibleWithPythonLegacy}}
else:
return json.dumps(self.actual_instance)
return json.dumps(to_jsonable_python(self.to_dict()))
{{/compatibleWithPythonLegacy}}

{{#compatibleWithPythonLegacy}}
Expand All @@ -198,10 +206,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
if self.actual_instance is None:
return None

if hasattr(self.actual_instance, "to_dict") and callable(self.actual_instance.to_dict):
return self.actual_instance.to_dict()
else:
return self.actual_instance
return _to_dict(self.actual_instance)
{{/compatibleWithPythonLegacy}}

def to_str(self) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ import pprint
from pydantic import StrictStr, Field
from typing import Union, List, Set, Optional, Dict
from typing_extensions import Literal, Self
{{#compatibleWithPythonLegacy}}
from pydantic_core import to_jsonable_python
{{#compatibleWithPythonLegacy}}


{{>_legacy_model_dict_helpers}}

{{/compatibleWithPythonLegacy}}
{{^compatibleWithPythonLegacy}}

{{>_composed_model_dict}}
{{/compatibleWithPythonLegacy}}

{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ONE_OF_SCHEMAS = [{{#oneOf}}"{{.}}"{{^-last}}, {{/-last}}{{/oneOf}}]
Expand Down Expand Up @@ -143,12 +147,16 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{#isContainer}}
# deserialize data into {{{dataType}}}
try:
data = json.loads(json_str)
{{#vendorExtensions.x-py-from-dict}}
data = {{{vendorExtensions.x-py-from-dict}}}
{{/vendorExtensions.x-py-from-dict}}
# validation
instance.{{vendorExtensions.x-py-name}} = json.loads(json_str)
instance.{{vendorExtensions.x-py-name}} = data
# assign value to actual_instance
instance.actual_instance = instance.{{vendorExtensions.x-py-name}}
match += 1
except (ValidationError, ValueError) as e:
except (ValidationError, ValueError, TypeError, AttributeError) as e:
error_messages.append(str(e))
{{/isContainer}}
{{^isContainer}}
Expand Down Expand Up @@ -199,7 +207,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{/compatibleWithPythonLegacy}}
{{^compatibleWithPythonLegacy}}
else:
return json.dumps(self.actual_instance)
return json.dumps(to_jsonable_python(self.to_dict()))
{{/compatibleWithPythonLegacy}}

{{#compatibleWithPythonLegacy}}
Expand All @@ -225,11 +233,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
if self.actual_instance is None:
return None

if hasattr(self.actual_instance, "to_dict") and callable(self.actual_instance.to_dict):
return self.actual_instance.to_dict()
else:
# primitive type
return self.actual_instance
return _to_dict(self.actual_instance)
{{/compatibleWithPythonLegacy}}

def to_str(self) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,60 @@ components:
$ref: '#/components/schemas/Pig'
nested_oneof_enum_string:
$ref: '#/components/schemas/OneOfEnumString'
OneOfContainer:
oneOf:
- type: string
- type: array
minItems: 1
items:
$ref: '#/components/schemas/Pig'
- type: object
additionalProperties:
$ref: '#/components/schemas/Pig'
- type: array
minItems: 1
items:
type: integer
- type: array
minItems: 1
items:
$ref: '#/components/schemas/EnumString1'
- type: array
minItems: 1
items:
$ref: '#/components/schemas/NullableClass'
AnyOfContainer:
anyOf:
- type: string
- type: array
minItems: 1
items:
$ref: '#/components/schemas/AnyOfPig'
- type: object
additionalProperties:
$ref: '#/components/schemas/AnyOfPig'
- type: array
minItems: 1
items:
type: integer
- type: array
minItems: 1
items:
$ref: '#/components/schemas/EnumString1'
- type: array
minItems: 1
items:
$ref: '#/components/schemas/NullableClass'
NestedUnionContainer:
oneOf:
- type: string
- type: array
items:
type: object
additionalProperties:
type: array
items:
$ref: '#/components/schemas/Pig'
Self-Reference-Model:
type: object
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,23 @@ def from_json(cls, json_str: str) -> Self:
error_messages.append(str(e))
# deserialize data into List[NestedModel]
try:
data = json.loads(json_str)
# validation
instance.anyof_schema_2_validator = json.loads(json_str)
instance.anyof_schema_2_validator = data
# assign value to actual_instance
instance.actual_instance = instance.anyof_schema_2_validator
return instance
except (ValidationError, ValueError) as e:
except (ValidationError, ValueError, TypeError, AttributeError) as e:
error_messages.append(str(e))
# deserialize data into Dict[str, NestedModel]
try:
data = json.loads(json_str)
# validation
instance.anyof_schema_3_validator = json.loads(json_str)
instance.anyof_schema_3_validator = data
# assign value to actual_instance
instance.actual_instance = instance.anyof_schema_3_validator
return instance
except (ValidationError, ValueError) as e:
except (ValidationError, ValueError, TypeError, AttributeError) as e:
error_messages.append(str(e))
# deserialize data into str
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,23 @@ def from_json(cls, json_str: str) -> Self:
error_messages.append(str(e))
# deserialize data into List[NestedModel]
try:
data = json.loads(json_str)
# validation
instance.oneof_schema_2_validator = json.loads(json_str)
instance.oneof_schema_2_validator = data
# assign value to actual_instance
instance.actual_instance = instance.oneof_schema_2_validator
match += 1
except (ValidationError, ValueError) as e:
except (ValidationError, ValueError, TypeError, AttributeError) as e:
error_messages.append(str(e))
# deserialize data into Dict[str, NestedModel]
try:
data = json.loads(json_str)
# validation
instance.oneof_schema_3_validator = json.loads(json_str)
instance.oneof_schema_3_validator = data
# assign value to actual_instance
instance.actual_instance = instance.oneof_schema_3_validator
match += 1
except (ValidationError, ValueError) as e:
except (ValidationError, ValueError, TypeError, AttributeError) as e:
error_messages.append(str(e))
# deserialize data into str
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ docs/AllOfWithSingleRef.md
docs/Animal.md
docs/AnotherFakeApi.md
docs/AnyOfColor.md
docs/AnyOfContainer.md
docs/AnyOfPig.md
docs/ArrayOfArrayOfModel.md
docs/ArrayOfArrayOfNumberOnly.md
Expand Down Expand Up @@ -74,11 +75,13 @@ docs/ModelField.md
docs/ModelReturn.md
docs/MultiArrays.md
docs/Name.md
docs/NestedUnionContainer.md
docs/NullableClass.md
docs/NullableProperty.md
docs/NumberOnly.md
docs/ObjectToTestAdditionalProperties.md
docs/ObjectWithDeprecatedFields.md
docs/OneOfContainer.md
docs/OneOfEnumString.md
docs/Order.md
docs/OuterComposite.md
Expand Down Expand Up @@ -149,6 +152,7 @@ petstore_api/models/all_of_super_model.py
petstore_api/models/all_of_with_single_ref.py
petstore_api/models/animal.py
petstore_api/models/any_of_color.py
petstore_api/models/any_of_container.py
petstore_api/models/any_of_pig.py
petstore_api/models/array_of_array_of_model.py
petstore_api/models/array_of_array_of_number_only.py
Expand Down Expand Up @@ -207,11 +211,13 @@ petstore_api/models/model_field.py
petstore_api/models/model_return.py
petstore_api/models/multi_arrays.py
petstore_api/models/name.py
petstore_api/models/nested_union_container.py
petstore_api/models/nullable_class.py
petstore_api/models/nullable_property.py
petstore_api/models/number_only.py
petstore_api/models/object_to_test_additional_properties.py
petstore_api/models/object_with_deprecated_fields.py
petstore_api/models/one_of_container.py
petstore_api/models/one_of_enum_string.py
petstore_api/models/order.py
petstore_api/models/outer_composite.py
Expand Down
3 changes: 3 additions & 0 deletions samples/openapi3/client/petstore/python-aiohttp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ Class | Method | HTTP request | Description
- [AllOfWithSingleRef](docs/AllOfWithSingleRef.md)
- [Animal](docs/Animal.md)
- [AnyOfColor](docs/AnyOfColor.md)
- [AnyOfContainer](docs/AnyOfContainer.md)
- [AnyOfPig](docs/AnyOfPig.md)
- [ArrayOfArrayOfModel](docs/ArrayOfArrayOfModel.md)
- [ArrayOfArrayOfNumberOnly](docs/ArrayOfArrayOfNumberOnly.md)
Expand Down Expand Up @@ -244,11 +245,13 @@ Class | Method | HTTP request | Description
- [ModelReturn](docs/ModelReturn.md)
- [MultiArrays](docs/MultiArrays.md)
- [Name](docs/Name.md)
- [NestedUnionContainer](docs/NestedUnionContainer.md)
- [NullableClass](docs/NullableClass.md)
- [NullableProperty](docs/NullableProperty.md)
- [NumberOnly](docs/NumberOnly.md)
- [ObjectToTestAdditionalProperties](docs/ObjectToTestAdditionalProperties.md)
- [ObjectWithDeprecatedFields](docs/ObjectWithDeprecatedFields.md)
- [OneOfContainer](docs/OneOfContainer.md)
- [OneOfEnumString](docs/OneOfEnumString.md)
- [Order](docs/Order.md)
- [OuterComposite](docs/OuterComposite.md)
Expand Down
Loading