Skip to content

Better compatibility for "required" vs. "nullable" #230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## 0.7.0 - Unreleased

### Breaking Changes

- Any request/response field that is not `required` and wasn't specified is now set to `UNSET` instead of `None`.
- Values that are `UNSET` will not be sent along in API calls

### Additions

- Added a `--custom-template-path` option for providing custom jinja2 templates (#231 - Thanks @erichulburd!).
- Better compatibility for "required" (whether or not the field must be included) and "nullable" (whether or not the field can be null) (#205 & #208). Thanks @bowenwr & @emannguitar!

## 0.6.2 - 2020-11-03

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from ...models.an_enum import AnEnum
from ...models.http_validation_error import HTTPValidationError
from ...types import UNSET, Unset


def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPValidationError]]:
Expand All @@ -34,57 +35,63 @@ def httpx_request(
*,
client: Client,
json_body: Dict[Any, Any],
string_prop: Optional[str] = "the default string",
datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"),
date_prop: Optional[datetime.date] = isoparse("1010-10-10").date(),
float_prop: Optional[float] = 3.14,
int_prop: Optional[int] = 7,
boolean_prop: Optional[bool] = False,
list_prop: Optional[List[AnEnum]] = None,
union_prop: Optional[Union[Optional[float], Optional[str]]] = "not a float",
enum_prop: Optional[AnEnum] = None,
string_prop: Union[Unset, str] = "the default string",
datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"),
date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(),
float_prop: Union[Unset, float] = 3.14,
int_prop: Union[Unset, int] = 7,
boolean_prop: Union[Unset, bool] = False,
list_prop: Union[Unset, List[AnEnum]] = UNSET,
union_prop: Union[Unset, float, str] = "not a float",
enum_prop: Union[Unset, AnEnum] = UNSET,
) -> httpx.Response[Union[None, HTTPValidationError]]:

json_datetime_prop = datetime_prop.isoformat() if datetime_prop else None
json_datetime_prop: Union[Unset, str] = UNSET
if not isinstance(datetime_prop, Unset):
json_datetime_prop = datetime_prop.isoformat()

json_date_prop = date_prop.isoformat() if date_prop else None
json_date_prop: Union[Unset, str] = UNSET
if not isinstance(date_prop, Unset):
json_date_prop = date_prop.isoformat()

if list_prop is None:
json_list_prop = None
else:
json_list_prop: Union[Unset, List[Any]] = UNSET
if not isinstance(list_prop, Unset):
json_list_prop = []
for list_prop_item_data in list_prop:
list_prop_item = list_prop_item_data.value

json_list_prop.append(list_prop_item)

if union_prop is None:
json_union_prop: Optional[Union[Optional[float], Optional[str]]] = None
json_union_prop: Union[Unset, float, str]
if isinstance(union_prop, Unset):
json_union_prop = UNSET
elif isinstance(union_prop, float):
json_union_prop = union_prop
else:
json_union_prop = union_prop

json_enum_prop = enum_prop.value if enum_prop else None
json_enum_prop: Union[Unset, AnEnum] = UNSET
if not isinstance(enum_prop, Unset):
json_enum_prop = enum_prop.value

params: Dict[str, Any] = {}
if string_prop is not None:
if string_prop is not UNSET:
params["string_prop"] = string_prop
if datetime_prop is not None:
if datetime_prop is not UNSET:
params["datetime_prop"] = json_datetime_prop
if date_prop is not None:
if date_prop is not UNSET:
params["date_prop"] = json_date_prop
if float_prop is not None:
if float_prop is not UNSET:
params["float_prop"] = float_prop
if int_prop is not None:
if int_prop is not UNSET:
params["int_prop"] = int_prop
if boolean_prop is not None:
if boolean_prop is not UNSET:
params["boolean_prop"] = boolean_prop
if list_prop is not None:
if list_prop is not UNSET:
params["list_prop"] = json_list_prop
if union_prop is not None:
if union_prop is not UNSET:
params["union_prop"] = json_union_prop
if enum_prop is not None:
if enum_prop is not UNSET:
params["enum_prop"] = json_enum_prop

json_json_body = json_body
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import Optional

import httpx

Client = httpx.Client

from typing import List, Optional, Union

from ...models.http_validation_error import HTTPValidationError
from ...types import UNSET, Unset


def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPValidationError]]:
if response.status_code == 200:
return None
if response.status_code == 422:
return HTTPValidationError.from_dict(cast(Dict[str, Any], response.json()))
return None


def _build_response(*, response: httpx.Response) -> httpx.Response[Union[None, HTTPValidationError]]:
return httpx.Response(
status_code=response.status_code,
content=response.content,
headers=response.headers,
parsed=_parse_response(response=response),
)


def httpx_request(
*,
client: Client,
query_param: Union[Unset, List[str]] = UNSET,
) -> httpx.Response[Union[None, HTTPValidationError]]:

json_query_param: Union[Unset, List[Any]] = UNSET
if not isinstance(query_param, Unset):
json_query_param = query_param

params: Dict[str, Any] = {}
if query_param is not UNSET:
params["query_param"] = json_query_param

response = client.request(
"get",
"/tests/optional_query_param/",
params=params,
)

return _build_response(response=response)
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

Client = httpx.Client

from typing import Optional
from typing import Optional, Union

from ...models.body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost
from ...models.http_validation_error import HTTPValidationError
from ...types import UNSET, Unset


def _parse_response(*, response: httpx.Response) -> Optional[Union[
Expand Down Expand Up @@ -37,12 +38,12 @@ def _build_response(*, response: httpx.Response) -> httpx.Response[Union[
def httpx_request(*,
client: Client,
multipart_data: BodyUploadFileTestsUploadPost,
keep_alive: Optional[bool] = None,
keep_alive: Union[Unset, bool] = UNSET,
) -> httpx.Response[Union[
None,
HTTPValidationError
]]:
if keep_alive is not None:
if keep_alive is not UNSET:
headers["keep-alive"] = keep_alive


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,27 @@

from ..models.an_enum import AnEnum
from ..models.different_enum import DifferentEnum
from ..types import UNSET, Unset


@attr.s(auto_attribs=True)
class AModel:
""" A Model for testing all the ways custom objects can be used """

an_enum_value: AnEnum
some_dict: Optional[Dict[Any, Any]]
a_camel_date_time: Union[datetime.datetime, datetime.date]
a_date: datetime.date
nested_list_of_enums: Optional[List[List[DifferentEnum]]] = None
attr_1_leading_digit: Optional[str] = None
required_not_nullable: str
some_dict: Optional[Dict[Any, Any]]
required_nullable: Optional[str]
nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET
attr_1_leading_digit: Union[Unset, str] = UNSET
not_required_nullable: Union[Unset, Optional[str]] = UNSET
not_required_not_nullable: Union[Unset, str] = UNSET

def to_dict(self) -> Dict[str, Any]:
an_enum_value = self.an_enum_value.value

some_dict = self.some_dict

if isinstance(self.a_camel_date_time, datetime.datetime):
a_camel_date_time = self.a_camel_date_time.isoformat()

Expand All @@ -32,9 +35,9 @@ def to_dict(self) -> Dict[str, Any]:

a_date = self.a_date.isoformat()

if self.nested_list_of_enums is None:
nested_list_of_enums = None
else:
required_not_nullable = self.required_not_nullable
nested_list_of_enums: Union[Unset, List[Any]] = UNSET
if not isinstance(self.nested_list_of_enums, Unset):
nested_list_of_enums = []
for nested_list_of_enums_item_data in self.nested_list_of_enums:
nested_list_of_enums_item = []
Expand All @@ -45,23 +48,36 @@ def to_dict(self) -> Dict[str, Any]:

nested_list_of_enums.append(nested_list_of_enums_item)

some_dict = self.some_dict if self.some_dict else None

attr_1_leading_digit = self.attr_1_leading_digit
required_nullable = self.required_nullable
not_required_nullable = self.not_required_nullable
not_required_not_nullable = self.not_required_not_nullable

return {
field_dict = {
"an_enum_value": an_enum_value,
"some_dict": some_dict,
"aCamelDateTime": a_camel_date_time,
"a_date": a_date,
"nested_list_of_enums": nested_list_of_enums,
"1_leading_digit": attr_1_leading_digit,
"required_not_nullable": required_not_nullable,
"some_dict": some_dict,
"required_nullable": required_nullable,
}
if nested_list_of_enums is not UNSET:
field_dict["nested_list_of_enums"] = nested_list_of_enums
if attr_1_leading_digit is not UNSET:
field_dict["1_leading_digit"] = attr_1_leading_digit
if not_required_nullable is not UNSET:
field_dict["not_required_nullable"] = not_required_nullable
if not_required_not_nullable is not UNSET:
field_dict["not_required_not_nullable"] = not_required_not_nullable

return field_dict

@staticmethod
def from_dict(d: Dict[str, Any]) -> "AModel":
an_enum_value = AnEnum(d["an_enum_value"])

some_dict = d["some_dict"]

def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime.datetime, datetime.date]:
a_camel_date_time: Union[datetime.datetime, datetime.date]
try:
Expand All @@ -78,8 +94,10 @@ def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime.datetime, d

a_date = isoparse(d["a_date"]).date()

required_not_nullable = d["required_not_nullable"]

nested_list_of_enums = []
for nested_list_of_enums_item_data in d.get("nested_list_of_enums") or []:
for nested_list_of_enums_item_data in d.get("nested_list_of_enums", UNSET) or []:
nested_list_of_enums_item = []
for nested_list_of_enums_item_item_data in nested_list_of_enums_item_data:
nested_list_of_enums_item_item = DifferentEnum(nested_list_of_enums_item_item_data)
Expand All @@ -88,13 +106,25 @@ def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime.datetime, d

nested_list_of_enums.append(nested_list_of_enums_item)

attr_1_leading_digit = d.get("1_leading_digit")
some_dict = d["some_dict"]

attr_1_leading_digit = d.get("1_leading_digit", UNSET)

required_nullable = d["required_nullable"]

not_required_nullable = d.get("not_required_nullable", UNSET)

not_required_not_nullable = d.get("not_required_not_nullable", UNSET)

return AModel(
an_enum_value=an_enum_value,
some_dict=some_dict,
a_camel_date_time=a_camel_date_time,
a_date=a_date,
required_not_nullable=required_not_nullable,
nested_list_of_enums=nested_list_of_enums,
some_dict=some_dict,
attr_1_leading_digit=attr_1_leading_digit,
required_nullable=required_nullable,
not_required_nullable=not_required_nullable,
not_required_not_nullable=not_required_not_nullable,
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ class BodyUploadFileTestsUploadPost:
def to_dict(self) -> Dict[str, Any]:
some_file = self.some_file.to_tuple()

return {
field_dict = {
"some_file": some_file,
}

return field_dict

@staticmethod
def from_dict(d: Dict[str, Any]) -> "BodyUploadFileTestsUploadPost":
some_file = d["some_file"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Union

import attr

from ..models.validation_error import ValidationError
from ..types import UNSET, Unset


@attr.s(auto_attribs=True)
class HTTPValidationError:
""" """

detail: Optional[List[ValidationError]] = None
detail: Union[Unset, List[ValidationError]] = UNSET

def to_dict(self) -> Dict[str, Any]:
if self.detail is None:
detail = None
else:
detail: Union[Unset, List[Any]] = UNSET
if not isinstance(self.detail, Unset):
detail = []
for detail_item_data in self.detail:
detail_item = detail_item_data.to_dict()

detail.append(detail_item)

return {
"detail": detail,
}
field_dict = {}
if detail is not UNSET:
field_dict["detail"] = detail

return field_dict

@staticmethod
def from_dict(d: Dict[str, Any]) -> "HTTPValidationError":
detail = []
for detail_item_data in d.get("detail") or []:
for detail_item_data in d.get("detail", UNSET) or []:
detail_item = ValidationError.from_dict(detail_item_data)

detail.append(detail_item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ def to_dict(self) -> Dict[str, Any]:
msg = self.msg
type = self.type

return {
field_dict = {
"loc": loc,
"msg": msg,
"type": type,
}

return field_dict

@staticmethod
def from_dict(d: Dict[str, Any]) -> "ValidationError":
loc = d["loc"]
Expand Down
Loading