Skip to content

Commit

Permalink
Support optional fields in models (#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy-Grigg authored Feb 23, 2024
1 parent 92ea22c commit 88655dc
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 15 deletions.
4 changes: 3 additions & 1 deletion src/ansys/openapi/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
__version__ = metadata.version("ansys-openapi-common")

from ._api_client import ApiClient
from ._base import ApiBase, ApiClientBase, ModelBase
from ._base import ApiBase, ApiClientBase, ModelBase, Unset, Unset_Type
from ._exceptions import ApiConnectionException, ApiException, AuthenticationWarning
from ._session import ApiClientFactory, OIDCSessionBuilder
from ._util import SessionConfiguration, generate_user_agent
Expand All @@ -22,4 +22,6 @@
"ApiBase",
"ApiClientBase",
"ModelBase",
"Unset",
"Unset_Type",
]
10 changes: 5 additions & 5 deletions src/ansys/openapi/common/_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from dateutil.parser import parse
import requests

from ._base import ApiClientBase, DeserializedType, ModelBase, PrimitiveType, SerializedType
from ._base import ApiClientBase, DeserializedType, ModelBase, PrimitiveType, SerializedType, Unset
from ._exceptions import ApiException
from ._util import SessionConfiguration, handle_response

Expand Down Expand Up @@ -133,7 +133,7 @@ def __call_api(
collection_formats: Optional[Dict[str, str]] = None,
_preload_content: bool = True,
_request_timeout: Union[float, Tuple[float, float], None] = None,
response_type_map: Optional[Dict[int, Union[str, None]]] = None,
response_type_map: Optional[Mapping[int, Union[str, None]]] = None,
) -> Union[requests.Response, DeserializedType, None]:
# header parameters
header_params = header_params or {}
Expand Down Expand Up @@ -272,7 +272,7 @@ def sanitize_for_serialization(self, obj: Any) -> Any:
obj_dict = {
obj.attribute_map[attr]: getattr(obj, attr)
for attr in obj.swagger_types
if getattr(obj, attr) is not None
if getattr(obj, attr) is not Unset
}

return {key: self.sanitize_for_serialization(val) for key, val in obj_dict.items()}
Expand Down Expand Up @@ -397,7 +397,7 @@ def call_api(
collection_formats: Optional[Dict[str, str]] = None,
_preload_content: bool = True,
_request_timeout: Union[float, Tuple[float, float], None] = None,
response_type_map: Optional[Dict[int, Union[str, None]]] = None,
response_type_map: Optional[Mapping[int, Union[str, None]]] = None,
) -> Union[requests.Response, DeserializedType, None]:
"""Make the HTTP request and return the deserialized data.
Expand Down Expand Up @@ -854,7 +854,7 @@ def __deserialize_model(
if key not in klass.swagger_types:
instance[key] = value
try:
klass_name = instance.get_real_child_model(data)
klass_name = instance.get_real_child_model(data) # type: ignore[arg-type]
if klass_name:
instance = self.__deserialize(data, klass_name) # type: ignore[assignment]
except NotImplementedError:
Expand Down
19 changes: 15 additions & 4 deletions src/ansys/openapi/common/_base/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import datetime
from enum import Enum
import pprint
from typing import Any, Dict, List, Optional, Tuple, Union
from typing import Any, Dict, List, Literal, Mapping, Optional, Tuple, Union

import requests

Expand Down Expand Up @@ -75,7 +75,7 @@ def to_str(self) -> str:
"""
return pprint.pformat(self.to_dict())

def get_real_child_model(self, data: Union[Dict, str]) -> str:
def get_real_child_model(self, data: Dict[str, str]) -> str:
"""Classes with discriminators will override this method and may change the method signature."""
raise NotImplementedError()

Expand Down Expand Up @@ -110,12 +110,23 @@ def call_api(
header_params: Union[Dict[str, Union[str, int]], None] = None,
body: Optional[DeserializedType] = None,
post_params: Optional[List[Tuple[str, Union[str, bytes]]]] = None,
files: Optional[Dict[str, str]] = None,
files: Optional[Mapping[str, str]] = None,
response_type: Optional[str] = None,
_return_http_data_only: Optional[bool] = None,
collection_formats: Optional[Dict[str, str]] = None,
_preload_content: bool = True,
_request_timeout: Union[float, Tuple[float, float], None] = None,
response_type_map: Optional[Dict[int, Union[str, None]]] = None,
response_type_map: Optional[Mapping[int, Union[str, None]]] = None,
) -> Union[requests.Response, DeserializedType, None]:
"""Provide method signature for calling the API."""


class _Unset:
@staticmethod
def __bool__() -> Literal[False]:
return False


Unset_Type = _Unset
Unset = _Unset()
"""Magic value to indicate a value has not been set."""
12 changes: 7 additions & 5 deletions tests/models/example_model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ansys.openapi.common import ModelBase
from ansys.openapi.common import ModelBase, Unset


class ExampleModel(ModelBase):
Expand Down Expand Up @@ -31,15 +31,17 @@ class ExampleModel(ModelBase):

def __init__(
self,
string_property=None,
int_property=None,
bool_property=None,
list_property=None,
string_property=Unset,
int_property=Unset,
bool_property=Unset,
list_property=Unset,
): # noqa: E501
self._string_property = None
self._int_property = None
self._bool_property = None
self._list_property = None
self._nullable_property = None
self._optional_property = None
self.discriminator = None
if string_property is not None:
self._string_property = string_property
Expand Down
38 changes: 38 additions & 0 deletions tests/test_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,44 @@ def test_serialize_model(self):
serialized_model = self._client.sanitize_for_serialization(model_instance)
assert serialized_model == model_dict

def test_serialize_model_null_values(self):
from . import models

self._client.setup_client(models)
model_instance = models.ExampleModel("foo", None, False, None)
model_dict = {
"Boolean": False,
"Integer": None,
"ListOfStrings": None,
"String": "foo",
}
serialized_model = self._client.sanitize_for_serialization(model_instance)
assert serialized_model == model_dict

def test_serialize_model_unset_values(self):
from . import models

self._client.setup_client(models)
model_instance = models.ExampleModel(int_property=3, list_property=["It's", "a", "list"])
model_dict = {
"Integer": 3,
"ListOfStrings": ["It's", "a", "list"],
}
serialized_model = self._client.sanitize_for_serialization(model_instance)
assert serialized_model == model_dict

def test_serialize_model_set_unset_and_null_values(self):
from . import models

self._client.setup_client(models)
model_instance = models.ExampleModel(int_property=None, list_property=["It's", "a", "list"])
model_dict = {
"Integer": None,
"ListOfStrings": ["It's", "a", "list"],
}
serialized_model = self._client.sanitize_for_serialization(model_instance)
assert serialized_model == model_dict

def test_serialize_enum_model(self):
from . import models

Expand Down

0 comments on commit 88655dc

Please sign in to comment.