Skip to content

Commit

Permalink
[Python] Handle nullable list items (OpenAPITools#17594)
Browse files Browse the repository at this point in the history
* fix nullable elements

* update type info in docs

* update examples
  • Loading branch information
changhc authored Jan 13, 2024
1 parent c6efe88 commit 968c6dc
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,11 @@ public String getTypeDeclaration(Schema p) {
if (ModelUtils.isArraySchema(p)) {
ArraySchema ap = (ArraySchema) p;
Schema inner = ap.getItems();
return getSchemaType(p) + "[" + getTypeDeclaration(inner) + "]";
String innerDeclaration = getTypeDeclaration(inner);
if (inner.getNullable() != null && inner.getNullable()) {
innerDeclaration = "Optional[" + innerDeclaration + "]";
}
return getSchemaType(p) + "[" + innerDeclaration + "]";
} else if (ModelUtils.isMapSchema(p)) {
Schema inner = ModelUtils.getAdditionalProperties(p);
return getSchemaType(p) + "[str, " + getTypeDeclaration(inner) + "]";
Expand Down Expand Up @@ -1748,10 +1752,21 @@ private PythonType arrayType(IJsonSchemaValidationProperties cp) {
pt.setType("List");
moduleImports.add("typing", "List");
}
pt.addTypeParam(getType(cp.getItems()));
pt.addTypeParam(collectionItemType(cp.getItems()));
return pt;
}

private PythonType collectionItemType(CodegenProperty itemCp) {
PythonType itemPt = getType(itemCp);
if (itemCp != null && itemCp.isNullable) {
moduleImports.add("typing", "Optional");
PythonType opt = new PythonType("Optional");
opt.addTypeParam(itemPt);
itemPt = opt;
}
return itemPt;
}

private PythonType stringType(IJsonSchemaValidationProperties cp) {

if (cp.getHasValidation()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,12 @@ components:
type: string
minItems: 0
maxItems: 3
array_of_nullable_float:
type: array
items:
type: number
format: float
nullable: true
array_array_of_integer:
type: array
items:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**array_of_string** | **List[str]** | | [optional]
**array_of_nullable_float** | **List[Optional[float]]** | | [optional]
**array_array_of_integer** | **List[List[int]]** | | [optional]
**array_array_of_model** | **List[List[ReadOnlyFirst]]** | | [optional]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Name | Type | Description | Notes
**date_prop** | **date** | | [optional]
**datetime_prop** | **datetime** | | [optional]
**array_nullable_prop** | **List[object]** | | [optional]
**array_and_items_nullable_prop** | **List[object]** | | [optional]
**array_items_nullable** | **List[object]** | | [optional]
**array_and_items_nullable_prop** | **List[Optional[object]]** | | [optional]
**array_items_nullable** | **List[Optional[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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class ArrayTest(BaseModel):
ArrayTest
""" # noqa: E501
array_of_string: Optional[Annotated[List[StrictStr], Field(min_length=0, max_length=3)]] = None
array_of_nullable_float: Optional[List[Optional[float]]] = None
array_array_of_integer: Optional[List[List[StrictInt]]] = None
array_array_of_model: Optional[List[List[ReadOnlyFirst]]] = None
__properties: ClassVar[List[str]] = ["array_of_string", "array_array_of_integer", "array_array_of_model"]
__properties: ClassVar[List[str]] = ["array_of_string", "array_of_nullable_float", "array_array_of_integer", "array_array_of_model"]

model_config = {
"populate_by_name": True,
Expand Down Expand Up @@ -94,6 +95,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:

_obj = cls.model_validate({
"array_of_string": obj.get("array_of_string"),
"array_of_nullable_float": obj.get("array_of_nullable_float"),
"array_array_of_integer": obj.get("array_array_of_integer"),
"array_array_of_model": [
[ReadOnlyFirst.from_dict(_inner_item) for _inner_item in _item]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class NullableClass(BaseModel):
date_prop: Optional[date] = None
datetime_prop: Optional[datetime] = None
array_nullable_prop: Optional[List[Dict[str, Any]]] = None
array_and_items_nullable_prop: Optional[List[Dict[str, Any]]] = None
array_items_nullable: Optional[List[Dict[str, Any]]] = None
array_and_items_nullable_prop: Optional[List[Optional[Dict[str, Any]]]] = None
array_items_nullable: Optional[List[Optional[Dict[str, Any]]]] = None
object_nullable_prop: Optional[Dict[str, Dict[str, Any]]] = None
object_and_items_nullable_prop: Optional[Dict[str, Dict[str, Any]]] = None
object_items_nullable: Optional[Dict[str, Dict[str, Any]]] = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**array_of_string** | **List[str]** | | [optional]
**array_of_nullable_float** | **List[float]** | | [optional]
**array_array_of_integer** | **List[List[int]]** | | [optional]
**array_array_of_model** | **List[List[ReadOnlyFirst]]** | | [optional]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ class ArrayTest(BaseModel):
ArrayTest
"""
array_of_string: Optional[conlist(StrictStr, max_items=3, min_items=0)] = None
array_of_nullable_float: Optional[conlist(float)] = None
array_array_of_integer: Optional[conlist(conlist(StrictInt))] = None
array_array_of_model: Optional[conlist(conlist(ReadOnlyFirst))] = None
__properties = ["array_of_string", "array_array_of_integer", "array_array_of_model"]
__properties = ["array_of_string", "array_of_nullable_float", "array_array_of_integer", "array_array_of_model"]

class Config:
"""Pydantic configuration"""
Expand Down Expand Up @@ -77,6 +78,7 @@ def from_dict(cls, obj: dict) -> ArrayTest:

_obj = ArrayTest.parse_obj({
"array_of_string": obj.get("array_of_string"),
"array_of_nullable_float": obj.get("array_of_nullable_float"),
"array_array_of_integer": obj.get("array_array_of_integer"),
"array_array_of_model": [
[ReadOnlyFirst.from_dict(_inner_item) for _inner_item in _item]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**array_of_string** | **List[str]** | | [optional]
**array_of_nullable_float** | **List[float]** | | [optional]
**array_array_of_integer** | **List[List[int]]** | | [optional]
**array_array_of_model** | **List[List[ReadOnlyFirst]]** | | [optional]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@


from typing import Any, Dict, List, Optional
from pydantic import BaseModel, StrictInt, StrictStr, conlist
from pydantic import BaseModel, StrictFloat, StrictInt, StrictStr, conlist
from petstore_api.models.read_only_first import ReadOnlyFirst

class ArrayTest(BaseModel):
"""
ArrayTest
"""
array_of_string: Optional[conlist(StrictStr, max_items=3, min_items=0)] = None
array_of_nullable_float: Optional[conlist(StrictFloat)] = None
array_array_of_integer: Optional[conlist(conlist(StrictInt))] = None
array_array_of_model: Optional[conlist(conlist(ReadOnlyFirst))] = None
additional_properties: Dict[str, Any] = {}
__properties = ["array_of_string", "array_array_of_integer", "array_array_of_model"]
__properties = ["array_of_string", "array_of_nullable_float", "array_array_of_integer", "array_array_of_model"]

class Config:
"""Pydantic configuration"""
Expand Down Expand Up @@ -84,6 +85,7 @@ def from_dict(cls, obj: dict) -> ArrayTest:

_obj = ArrayTest.parse_obj({
"array_of_string": obj.get("array_of_string"),
"array_of_nullable_float": obj.get("array_of_nullable_float"),
"array_array_of_integer": obj.get("array_array_of_integer"),
"array_array_of_model": [
[ReadOnlyFirst.from_dict(_inner_item) for _inner_item in _item]
Expand Down
1 change: 1 addition & 0 deletions samples/openapi3/client/petstore/python/docs/ArrayTest.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**array_of_string** | **List[str]** | | [optional]
**array_of_nullable_float** | **List[Optional[float]]** | | [optional]
**array_array_of_integer** | **List[List[int]]** | | [optional]
**array_array_of_model** | **List[List[ReadOnlyFirst]]** | | [optional]

Expand Down
4 changes: 2 additions & 2 deletions samples/openapi3/client/petstore/python/docs/NullableClass.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Name | Type | Description | Notes
**date_prop** | **date** | | [optional]
**datetime_prop** | **datetime** | | [optional]
**array_nullable_prop** | **List[object]** | | [optional]
**array_and_items_nullable_prop** | **List[object]** | | [optional]
**array_items_nullable** | **List[object]** | | [optional]
**array_and_items_nullable_prop** | **List[Optional[object]]** | | [optional]
**array_items_nullable** | **List[Optional[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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import re # noqa: F401
import json

from pydantic import BaseModel, Field, StrictInt, StrictStr
from pydantic import BaseModel, Field, StrictFloat, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from petstore_api.models.read_only_first import ReadOnlyFirst
Expand All @@ -29,10 +29,11 @@ class ArrayTest(BaseModel):
ArrayTest
""" # noqa: E501
array_of_string: Optional[Annotated[List[StrictStr], Field(min_length=0, max_length=3)]] = None
array_of_nullable_float: Optional[List[Optional[StrictFloat]]] = None
array_array_of_integer: Optional[List[List[StrictInt]]] = None
array_array_of_model: Optional[List[List[ReadOnlyFirst]]] = None
additional_properties: Dict[str, Any] = {}
__properties: ClassVar[List[str]] = ["array_of_string", "array_array_of_integer", "array_array_of_model"]
__properties: ClassVar[List[str]] = ["array_of_string", "array_of_nullable_float", "array_array_of_integer", "array_array_of_model"]

model_config = {
"populate_by_name": True,
Expand Down Expand Up @@ -102,6 +103,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:

_obj = cls.model_validate({
"array_of_string": obj.get("array_of_string"),
"array_of_nullable_float": obj.get("array_of_nullable_float"),
"array_array_of_integer": obj.get("array_array_of_integer"),
"array_array_of_model": [
[ReadOnlyFirst.from_dict(_inner_item) for _inner_item in _item]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class NullableClass(BaseModel):
date_prop: Optional[date] = None
datetime_prop: Optional[datetime] = None
array_nullable_prop: Optional[List[Dict[str, Any]]] = None
array_and_items_nullable_prop: Optional[List[Dict[str, Any]]] = None
array_items_nullable: Optional[List[Dict[str, Any]]] = None
array_and_items_nullable_prop: Optional[List[Optional[Dict[str, Any]]]] = None
array_items_nullable: Optional[List[Optional[Dict[str, Any]]]] = None
object_nullable_prop: Optional[Dict[str, Dict[str, Any]]] = None
object_and_items_nullable_prop: Optional[Dict[str, Dict[str, Any]]] = None
object_items_nullable: Optional[Dict[str, Dict[str, Any]]] = None
Expand Down

0 comments on commit 968c6dc

Please sign in to comment.