Skip to content

feat: Add allOf support for model definitions BNCH-18722 - #12

Merged
packyg merged 5 commits into
main-v.0.7.0from
update-allOf-support
Dec 8, 2020
Merged

feat: Add allOf support for model definitions BNCH-18722#12
packyg merged 5 commits into
main-v.0.7.0from
update-allOf-support

Conversation

@packyg

@packygpackyg commented Dec 5, 2020

Copy link
Copy Markdown

Collapses the child elements into one, without class heirarchy, mixins, etc

This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new main-v.0.7.0, modified for the refactored upstream.

This should bring main-v.0.7.0 up to par with main for the features we implemented in our fork (dropping our Unset implementation for theirs)


We cannot really cut over to the upstream until a couple of issues are addressed:

See also: openapi-generators#98 (upstream issue by @dtkav) that this implements - we should try upstreaming this if all goes well

@packyg

Copy link
Copy Markdown
Author

@adamrp is a non-blocking reviewer - just spreading context on the codegen/SDK

@bowenwrbowenwr left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What a journey. Thanks for all your efforts on this @packyg.

I generated a client with this and tried running a subset of our integration tests and they fail. In general, this PR looks OK to me but in 296ffb6 we introduce something like if not isinstance(some_prop, Unset): which is causing an error.

For example in list_boxes.py generated from this:

 json_sort: Union[Unset, ListBoxesSort] = UNSET
if not isinstance(sort, Unset):
json_sort = sort

Causes TypeError: isinstance() arg 2 must be a type or tuple of types. I think we need to be using sort == UNSET.

Something to visit next week as we close in on syncing everything up.

@dtkavdtkav left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one!

Comment on lines +64 to +66
new_optional_props = [op for op in self.optional_properties if op.name != prop.name]
self.optional_properties.clear()
self.optional_properties.extend(new_optional_props)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, what's the difference between this and

self.optional_properties = [op for op in self.optional_properties if op.name != prop.name]

?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dtkav There isn't, except this class is marked with @attr.s(auto_attribs=True, frozen=True) so errors if I attempt to set the property

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, TIL - thanks!

@packyg

Copy link
Copy Markdown
Author

Causes TypeError: isinstance() arg 2 must be a type or tuple of types. I think we need to be using sort == UNSET.

Something to visit next week as we close in on syncing everything up.

Hmm I'll need to look at this more. The upstream is using the isinstance pattern and it seems to be working for them

@adamrp

Copy link
Copy Markdown

Causes TypeError: isinstance() arg 2 must be a type or tuple of types. I think we need to be using sort == UNSET.
Something to visit next week as we close in on syncing everything up.

Hmm I'll need to look at this more. The upstream is using the isinstance pattern and it seems to be working for them

Don't quote me on this, but I think isinstance has to take Python types (not Typing types) -- e.g., a class name or a tuple of class names

@packyg

Copy link
Copy Markdown
Author

Don't quote me on this, but I think isinstance has to take Python types (not Typing types) -- e.g., a class name or a tuple of class names

That's what I don't understand - Unset is a class, which UNSET is an instance of

@adamrpadamrp left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving, although I wish I knew why isinstance is failing... 🤔

@bowenwr

Copy link
Copy Markdown

Approving, although I wish I knew why isinstance is failing... 🤔

In my example it's because sort is passed as None which causes {NameError}name 'Unset' is not defined.

The generated client is looking for Union[Unset, ListBoxesSort]. We could change all the defaults in the SDK to use UNSET but I hate that it then exposes a pretty specific implementation detail.

Maybe we could persuade the maintainers to also check is not None but more likely I guess we could map None -> Unset for our cases where needed.

@packyg

packyg commented Dec 7, 2020

Copy link
Copy Markdown
Author

Maybe we could persuade the maintainers to also check is not None but more likely I guess we could map None -> Unset for our cases where needed.

@bowenwr We don't want them to do that, at least for JSON serialization, do we? If we did that it would be treating Unset the same as None and we're back to not having a distinction between unset/semantically meaningful None

As for URL and QS parameters -that's a different story, I could see the use in treating UNSET and None the same.


Still don't know why checking isinstance(None, Unset) causes a NameError - did Unset not get imported?


As far as for now - I think it'd be OK for us to use this implementation detail in the SDK since it's so tightly coupled to the generated client.

@bowenwr

Copy link
Copy Markdown

Maybe we could persuade the maintainers to also check is not None but more likely I guess we could map None -> Unset for our cases where needed.

@bowenwr We don't want them to do that, at least for JSON serialization, do we? If we did that it would be treating Unset the same as None and we're back to not having a distinction between unset/semantically meaningful None

As for URL and QS parameters -that's a different story, I could see the use in treating UNSET and None the same.

Still don't know why checking isinstance(None, Unset) causes a NameError - did Unset not get imported?

As far as for now - I think it'd be OK for us to use this implementation detail in the SDK since it's so tightly coupled to the generated client.

@packyg

As for URL and QS parameters -that's a different story, I could see the use in treating UNSET and None the same.

Yes, this is the case to which I'm referring. Specifically a query param. For JSON serialization, you're correct.

did Unset not get imported?

It's imported.

Generated endpoint:

fromtypingimportAny, Dict, Optional, Unionimporthttpxfrom ...clientimportClientfrom ...models.bad_request_errorimportBadRequestErrorfrom ...models.box_listimportBoxListfrom ...models.list_boxes_sortimportListBoxesSortfrom ...typesimportUNSET, Response, Unsetdef_get_kwargs(
*,
client: Client,
page_size: Union[Unset, int] =50,
next_token: Union[Unset, str] =UNSET,
sort: Union[Unset, ListBoxesSort] =ListBoxesSort.MODIFIEDATDESC,
schema_id: Union[Unset, str] =UNSET,
modified_at: Union[Unset, str] =UNSET,
name: Union[Unset, str] =UNSET,
name_includes: Union[Unset, str] =UNSET,
empty_positions: Union[Unset, int] =UNSET,
empty_positionsgte: Union[Unset, int] =UNSET,
empty_positionsgt: Union[Unset, int] =UNSET,
empty_positionslte: Union[Unset, int] =UNSET,
empty_positionslt: Union[Unset, int] =UNSET,
empty_containers: Union[Unset, int] =UNSET,
empty_containersgte: Union[Unset, int] =UNSET,
empty_containersgt: Union[Unset, int] =UNSET,
empty_containerslte: Union[Unset, int] =UNSET,
empty_containerslt: Union[Unset, int] =UNSET,
ancestor_storage_id: Union[Unset, str] =UNSET,
storage_contents_id: Union[Unset, str] =UNSET,
storage_contents_ids: Union[Unset, str] =UNSET,
archive_reason: Union[Unset, str] =UNSET,
ids: Union[Unset, str] =UNSET,
barcodes: Union[Unset, str] =UNSET,
) ->Dict[str, Any]:
url="{}/boxes".format(client.base_url)
headers: Dict[str, Any] =client.get_headers()
json_sort: Union[Unset, ListBoxesSort] =UNSETifnotisinstance(sort, Unset):
json_sort=sortparams: Dict[str, Any] = {}
ifpage_sizeisnotUNSET:
params["pageSize"] =page_sizeifnext_tokenisnotUNSET:
params["nextToken"] =next_tokenifsortisnotUNSET:
params["sort"] =json_sortifschema_idisnotUNSET:
params["schemaId"] =schema_idifmodified_atisnotUNSET:
params["modifiedAt"] =modified_atifnameisnotUNSET:
params["name"] =nameifname_includesisnotUNSET:
params["nameIncludes"] =name_includesifempty_positionsisnotUNSET:
params["emptyPositions"] =empty_positionsifempty_positionsgteisnotUNSET:
params["emptyPositions.gte"] =empty_positionsgteifempty_positionsgtisnotUNSET:
params["emptyPositions.gt"] =empty_positionsgtifempty_positionslteisnotUNSET:
params["emptyPositions.lte"] =empty_positionslteifempty_positionsltisnotUNSET:
params["emptyPositions.lt"] =empty_positionsltifempty_containersisnotUNSET:
params["emptyContainers"] =empty_containersifempty_containersgteisnotUNSET:
params["emptyContainers.gte"] =empty_containersgteifempty_containersgtisnotUNSET:
params["emptyContainers.gt"] =empty_containersgtifempty_containerslteisnotUNSET:
params["emptyContainers.lte"] =empty_containerslteifempty_containersltisnotUNSET:
params["emptyContainers.lt"] =empty_containersltifancestor_storage_idisnotUNSET:
params["ancestorStorageId"] =ancestor_storage_idifstorage_contents_idisnotUNSET:
params["storageContentsId"] =storage_contents_idifstorage_contents_idsisnotUNSET:
params["storageContentsIds"] =storage_contents_idsifarchive_reasonisnotUNSET:
params["archiveReason"] =archive_reasonifidsisnotUNSET:
params["ids"] =idsifbarcodesisnotUNSET:
params["barcodes"] =barcodesreturn {
"url": url,
"headers": headers,
"cookies": client.get_cookies(),
"timeout": client.get_timeout(),
"params": params,
}
def_parse_response(*, response: httpx.Response) ->Optional[Union[BoxList, BadRequestError]]:
ifresponse.status_code==200:
response_200=BoxList.from_dict(response.json())
returnresponse_200ifresponse.status_code==400:
response_400=BadRequestError.from_dict(response.json())
returnresponse_400returnNonedef_build_response(*, response: httpx.Response) ->Response[Union[BoxList, BadRequestError]]:
returnResponse(
status_code=response.status_code,
content=response.content,
headers=response.headers,
parsed=_parse_response(response=response),
)
defsync_detailed(
*,
client: Client,
page_size: Union[Unset, int] =50,
next_token: Union[Unset, str] =UNSET,
sort: Union[Unset, ListBoxesSort] =ListBoxesSort.MODIFIEDATDESC,
schema_id: Union[Unset, str] =UNSET,
modified_at: Union[Unset, str] =UNSET,
name: Union[Unset, str] =UNSET,
name_includes: Union[Unset, str] =UNSET,
empty_positions: Union[Unset, int] =UNSET,
empty_positionsgte: Union[Unset, int] =UNSET,
empty_positionsgt: Union[Unset, int] =UNSET,
empty_positionslte: Union[Unset, int] =UNSET,
empty_positionslt: Union[Unset, int] =UNSET,
empty_containers: Union[Unset, int] =UNSET,
empty_containersgte: Union[Unset, int] =UNSET,
empty_containersgt: Union[Unset, int] =UNSET,
empty_containerslte: Union[Unset, int] =UNSET,
empty_containerslt: Union[Unset, int] =UNSET,
ancestor_storage_id: Union[Unset, str] =UNSET,
storage_contents_id: Union[Unset, str] =UNSET,
storage_contents_ids: Union[Unset, str] =UNSET,
archive_reason: Union[Unset, str] =UNSET,
ids: Union[Unset, str] =UNSET,
barcodes: Union[Unset, str] =UNSET,
) ->Response[Union[BoxList, BadRequestError]]:
kwargs=_get_kwargs(
client=client,
page_size=page_size,
next_token=next_token,
sort=sort,
schema_id=schema_id,
modified_at=modified_at,
name=name,
name_includes=name_includes,
empty_positions=empty_positions,
empty_positionsgte=empty_positionsgte,
empty_positionsgt=empty_positionsgt,
empty_positionslte=empty_positionslte,
empty_positionslt=empty_positionslt,
empty_containers=empty_containers,
empty_containersgte=empty_containersgte,
empty_containersgt=empty_containersgt,
empty_containerslte=empty_containerslte,
empty_containerslt=empty_containerslt,
ancestor_storage_id=ancestor_storage_id,
storage_contents_id=storage_contents_id,
storage_contents_ids=storage_contents_ids,
archive_reason=archive_reason,
ids=ids,
barcodes=barcodes,
)
response=httpx.get(
**kwargs,
)
return_build_response(response=response)
defsync(
*,
client: Client,
page_size: Union[Unset, int] =50,
next_token: Union[Unset, str] =UNSET,
sort: Union[Unset, ListBoxesSort] =ListBoxesSort.MODIFIEDATDESC,
schema_id: Union[Unset, str] =UNSET,
modified_at: Union[Unset, str] =UNSET,
name: Union[Unset, str] =UNSET,
name_includes: Union[Unset, str] =UNSET,
empty_positions: Union[Unset, int] =UNSET,
empty_positionsgte: Union[Unset, int] =UNSET,
empty_positionsgt: Union[Unset, int] =UNSET,
empty_positionslte: Union[Unset, int] =UNSET,
empty_positionslt: Union[Unset, int] =UNSET,
empty_containers: Union[Unset, int] =UNSET,
empty_containersgte: Union[Unset, int] =UNSET,
empty_containersgt: Union[Unset, int] =UNSET,
empty_containerslte: Union[Unset, int] =UNSET,
empty_containerslt: Union[Unset, int] =UNSET,
ancestor_storage_id: Union[Unset, str] =UNSET,
storage_contents_id: Union[Unset, str] =UNSET,
storage_contents_ids: Union[Unset, str] =UNSET,
archive_reason: Union[Unset, str] =UNSET,
ids: Union[Unset, str] =UNSET,
barcodes: Union[Unset, str] =UNSET,
) ->Optional[Union[BoxList, BadRequestError]]:
""" List boxes """returnsync_detailed(
client=client,
page_size=page_size,
next_token=next_token,
sort=sort,
schema_id=schema_id,
modified_at=modified_at,
name=name,
name_includes=name_includes,
empty_positions=empty_positions,
empty_positionsgte=empty_positionsgte,
empty_positionsgt=empty_positionsgt,
empty_positionslte=empty_positionslte,
empty_positionslt=empty_positionslt,
empty_containers=empty_containers,
empty_containersgte=empty_containersgte,
empty_containersgt=empty_containersgt,
empty_containerslte=empty_containerslte,
empty_containerslt=empty_containerslt,
ancestor_storage_id=ancestor_storage_id,
storage_contents_id=storage_contents_id,
storage_contents_ids=storage_contents_ids,
archive_reason=archive_reason,
ids=ids,
barcodes=barcodes,
).parsedasyncdefasyncio_detailed(
*,
client: Client,
page_size: Union[Unset, int] =50,
next_token: Union[Unset, str] =UNSET,
sort: Union[Unset, ListBoxesSort] =ListBoxesSort.MODIFIEDATDESC,
schema_id: Union[Unset, str] =UNSET,
modified_at: Union[Unset, str] =UNSET,
name: Union[Unset, str] =UNSET,
name_includes: Union[Unset, str] =UNSET,
empty_positions: Union[Unset, int] =UNSET,
empty_positionsgte: Union[Unset, int] =UNSET,
empty_positionsgt: Union[Unset, int] =UNSET,
empty_positionslte: Union[Unset, int] =UNSET,
empty_positionslt: Union[Unset, int] =UNSET,
empty_containers: Union[Unset, int] =UNSET,
empty_containersgte: Union[Unset, int] =UNSET,
empty_containersgt: Union[Unset, int] =UNSET,
empty_containerslte: Union[Unset, int] =UNSET,
empty_containerslt: Union[Unset, int] =UNSET,
ancestor_storage_id: Union[Unset, str] =UNSET,
storage_contents_id: Union[Unset, str] =UNSET,
storage_contents_ids: Union[Unset, str] =UNSET,
archive_reason: Union[Unset, str] =UNSET,
ids: Union[Unset, str] =UNSET,
barcodes: Union[Unset, str] =UNSET,
) ->Response[Union[BoxList, BadRequestError]]:
kwargs=_get_kwargs(
client=client,
page_size=page_size,
next_token=next_token,
sort=sort,
schema_id=schema_id,
modified_at=modified_at,
name=name,
name_includes=name_includes,
empty_positions=empty_positions,
empty_positionsgte=empty_positionsgte,
empty_positionsgt=empty_positionsgt,
empty_positionslte=empty_positionslte,
empty_positionslt=empty_positionslt,
empty_containers=empty_containers,
empty_containersgte=empty_containersgte,
empty_containersgt=empty_containersgt,
empty_containerslte=empty_containerslte,
empty_containerslt=empty_containerslt,
ancestor_storage_id=ancestor_storage_id,
storage_contents_id=storage_contents_id,
storage_contents_ids=storage_contents_ids,
archive_reason=archive_reason,
ids=ids,
barcodes=barcodes,
)
asyncwithhttpx.AsyncClient() as_client:
response=await_client.get(**kwargs)
return_build_response(response=response)
asyncdefasyncio(
*,
client: Client,
page_size: Union[Unset, int] =50,
next_token: Union[Unset, str] =UNSET,
sort: Union[Unset, ListBoxesSort] =ListBoxesSort.MODIFIEDATDESC,
schema_id: Union[Unset, str] =UNSET,
modified_at: Union[Unset, str] =UNSET,
name: Union[Unset, str] =UNSET,
name_includes: Union[Unset, str] =UNSET,
empty_positions: Union[Unset, int] =UNSET,
empty_positionsgte: Union[Unset, int] =UNSET,
empty_positionsgt: Union[Unset, int] =UNSET,
empty_positionslte: Union[Unset, int] =UNSET,
empty_positionslt: Union[Unset, int] =UNSET,
empty_containers: Union[Unset, int] =UNSET,
empty_containersgte: Union[Unset, int] =UNSET,
empty_containersgt: Union[Unset, int] =UNSET,
empty_containerslte: Union[Unset, int] =UNSET,
empty_containerslt: Union[Unset, int] =UNSET,
ancestor_storage_id: Union[Unset, str] =UNSET,
storage_contents_id: Union[Unset, str] =UNSET,
storage_contents_ids: Union[Unset, str] =UNSET,
archive_reason: Union[Unset, str] =UNSET,
ids: Union[Unset, str] =UNSET,
barcodes: Union[Unset, str] =UNSET,
) ->Optional[Union[BoxList, BadRequestError]]:
""" List boxes """return (
awaitasyncio_detailed(
client=client,
page_size=page_size,
next_token=next_token,
sort=sort,
schema_id=schema_id,
modified_at=modified_at,
name=name,
name_includes=name_includes,
empty_positions=empty_positions,
empty_positionsgte=empty_positionsgte,
empty_positionsgt=empty_positionsgt,
empty_positionslte=empty_positionslte,
empty_positionslt=empty_positionslt,
empty_containers=empty_containers,
empty_containersgte=empty_containersgte,
empty_containersgt=empty_containersgt,
empty_containerslte=empty_containerslte,
empty_containerslt=empty_containerslt,
ancestor_storage_id=ancestor_storage_id,
storage_contents_id=storage_contents_id,
storage_contents_ids=storage_contents_ids,
archive_reason=archive_reason,
ids=ids,
barcodes=barcodes,
)
).parsed

@bowenwr

Copy link
Copy Markdown

To be clear, the comments about Unset shouldn't hold up this PR. I just wanna capture it as part of our known "closing the gap" series.

@packyg
packyg changed the base branch from main-v.0.7.0 to main-v.0.7.1December 8, 2020 23:41
@packyg
packyg changed the base branch from main-v.0.7.1 to main-v.0.7.0December 8, 2020 23:41
@packyg
packyg merged commit 782bbd0 into main-v.0.7.0Dec 8, 2020
@packyg
packyg deleted the update-allOf-support branch December 8, 2020 23:47
packyg added a commit that referenced this pull request Dec 8, 2020
Collapses the child elements into one, without class heirarchy, mixins, etc
This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new `main-v.0.7.0`, modified for the refactored upstream.
This should bring `main-v.0.7.1` up to par with `main` for the features we implemented in our fork (dropping our `Unset` implementation for theirs)
packyg added a commit that referenced this pull request Dec 9, 2020
Collapses the child elements into one, without class heirarchy, mixins, etc
This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new `main-v.0.7.0`, modified for the refactored upstream.
This should bring `main-v.0.7.1` up to par with `main` for the features we implemented in our fork (dropping our `Unset` implementation for theirs)
packyg added a commit that referenced this pull request Dec 9, 2020
Collapses the child elements into one, without class heirarchy, mixins, etc
This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new `main-v.0.7.0`, modified for the refactored upstream.
This should bring `main-v.0.7.1` up to par with `main` for the features we implemented in our fork (dropping our `Unset` implementation for theirs)
bowenwr pushed a commit that referenced this pull request Jan 5, 2021
Collapses the child elements into one, without class heirarchy, mixins, etc
This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new `main-v.0.7.0`, modified for the refactored upstream.
This should bring `main-v.0.7.1` up to par with `main` for the features we implemented in our fork (dropping our `Unset` implementation for theirs)
packyg added a commit that referenced this pull request Jan 13, 2021
Collapses the child elements into one, without class heirarchy, mixins, etc
This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new `main-v.0.7.0`, modified for the refactored upstream.
This should bring `main-v.0.7.1` up to par with `main` for the features we implemented in our fork (dropping our `Unset` implementation for theirs)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@packyg@adamrp@bowenwr@dtkav