-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
[python] fix typing for API responses #16802
Conversation
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
This PullRequest removes the following arguments
|
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
This PullRequest is the first step in achieving #16788. |
I have seen #16789. My idea is to split call_api into 3 functions It is essential to remove _preload_content and _return_http_data_only. We would like to achieve the following in the end. @validate_call
def get(self) -> GetResponse:
...
# param_serialize returns a Param class that call_api can easily process
param: Param = self.param_serialize(...)
# call_api is a low-level function that takes Param and always returns RESTResponse
res: RESTResponse = util.call_api(param)
# response_deserialize is a function that receives RESTResponse and deserializes it, always returning ApiResponse[Any].
return util.response_deserialize(res, ...).data
@validate_call
def get_with_http_info(self) -> ApiResponse[GetResponse]:
...
param: Param = self.param_serialize(...)
res: RESTResponse = util.call_api(param)
return util.response_deserialize(res, ...)
@validate_call
def get_with_preload_content(self) -> bytes:
"""
Equivalent to current preload_content.
This is to avoid unnecessary deserialization.
"""
...
param: Param = self.param_serialize(...)
res: RESTResponse = util.call_api(param)
return res.data
@validate_call
def get_with_async(self) -> ApplyResult:
"""
Equivalent to current async_req.
"""
...
param: Param = self.param_serialize(...)
res: ApplyResult = util.call_api_async(param)
return res @validate_call
async def get(self) -> ApiResponse[GetResponse]:
...
param: Param = self.param_serialize(...)
res: RESTResponse = await util.call_api_aiohttp(param)
return util.response_deserialize(res, ...) |
modules/openapi-generator/src/main/resources/python/api_response.mustache
Show resolved
Hide resolved
This pull request involves many disruptive changes and I would like your input. |
I think it's a good idea to remove these flags that modify the return value type of the API call methods. Also using I see these use-cases for
I think the new method
|
👍
good idea to include urllib3/aiohttp response object in the ApiResponse object |
Not against
In other words, the (some other client generators use similar design to handle edge cases) |
Good idea 👍 |
What about moving |
Signed-off-by: ふぁ <[email protected]>
As pointed out, |
Signed-off-by: ふぁ <[email protected]>
036ed28
to
178d493
Compare
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for these changes, I'm excited about the clean typing!
modules/openapi-generator/src/main/resources/python/partial_api_args.mustache
Outdated
Show resolved
Hide resolved
modules/openapi-generator/src/main/resources/python/api.mustache
Outdated
Show resolved
Hide resolved
**kwargs, | ||
|
||
@validate_call | ||
{{#asyncio}}async {{/asyncio}}def {{operationId}}_without_preload_content{{>partial_api_args}} -> RESTResponseType: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of _without_preload_content
, this could also be called _raw
to be shorter.
Just a suggestion. If you go with it, best make sure name clashes are handled, because I find it sort of likely that there are REST APIs that have both a get
and a get_raw
endpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of a way to handle name conflicts, any ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you could export the suffix to a parameter upon generation? That way it would work for most use cases but if someone happens to have conflicts they can just choose a different one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of
_without_preload_content
, this could also be called_raw
to be shorter.Just a suggestion. If you go with it, best make sure name clashes are handled, because I find it sort of likely that there are REST APIs that have both a
get
and aget_raw
endpoint.
If the OpenAPI method is called get_raw, the generated method would be called get_raw_raw, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For an OpenAPI method get, the raw endpoint would be called get_raw and clash with the OpenAPI method get_raw.
I would like it best if the generator automatically added a trailing underscore to make sure the raw function name is unique. Maybe we should discuss this in a separate issue though, it could be solved after this PR is merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. It's already the case with the previous functions though, right? (One could have defined q `get_with_http_info| OpenAPI method, and it would have clashed too)
Why don't we keep it simple here, with the "long" name?
The preload content feature was hidden before behind a very special flag, I would assume it wasn't really used that much by external callers and mostly used internally, in which case:
- The long name is fine: internal calls don't care, external users are probably going to use it seldomly anyway.
- I'm not even sure if this would be actually used at all.
So I would say: keep the current long name for now.
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
samples/openapi3/client/petstore/python-aiohttp/petstore_api/api/user_api.py
Outdated
Show resolved
Hide resolved
modules/openapi-generator/src/main/resources/python/partial_api.mustache
Outdated
Show resolved
Hide resolved
{{/allParams}} | ||
**kwargs, | ||
@validate_call | ||
{{#asyncio}}async {{/asyncio}}def {{operationId}}_without_preload_content{{>partial_api_args}} -> RESTResponseType: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every generated client will only ever support one backend library at a time. That's why I'm not sure the RESTResponseType
alias is useful in the final generated client.
For me, not using async or tornado, seeing urllib3.HTTPResponse
here would be most informative when working with the generated client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @robertschweizer : I don't think there's a need to abstract the underlying response from the actual client.
The client itself is already a bit abstracted because it's doing internal manipulation of the parameters but the response type doesn't do anything special, and at best it would be a downgraded version of the underlying response.
Since it's being used only in specific cases (when the caller only wants to do the HTTP call without the model API), and that it's not possible anyway to use multiple HTTP clients at the same, I would just remove the abstraction and return the HTTP réponse object from the underlying library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separating the generated client(urllib3/aiohttp) from the api(api.mustache
) will eliminate the need to modify api.mustache
when adding a new RESTClientObject
.
My idea is to be able to add a new RESTClientObject with minimal changes.
(In the future I may add httpx as a client.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I see. Re-reading the change, we can maybe try to remove RESTReponse
instead, but keep the type alias RESTReponseType
for the use case you mentioned.
This can be done in a subsequent PR though.
Thanks for the big work! I don't have too much time to review in details until beginning of November, but it looks really good from what I've seen. I would suggest to keep it focused though: it's already addressing a lot of different topics (typing, code cleanup, cosmetics, etc.), and although the final result looks much much better than before, I think it's also fine to not have it perfect and had new changes on top of it afterwards. |
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Signed-off-by: ふぁ <[email protected]>
Awesome work 👍 Let's go with what you've so far and we can file separate PRs to further improve the python client generator if needed. |
This was removed in OpenAPITools#16802, but using a higher value than 1, or at least making this configurable makes complete sense. Without this, we get a lot of these log messages: [ WARNING] Connection pool is full, discarding connection:
This was removed in #16802, but using a higher value than 1, or at least making this configurable makes complete sense. Without this, we get a lot of these log messages: [ WARNING] Connection pool is full, discarding connection:
PR checklist
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*
.For Windows users, please run the script in Git BASH.
master
(upcoming 7.1.0 minor release - breaking changes with fallbacks),8.0.x
(breaking changes without fallbacks)