python: generate Pydantic v2 + typing complete code#16624
python: generate Pydantic v2 + typing complete code#16624wing328 merged 32 commits intoOpenAPITools:masterfrom
Conversation
bdc8789 to
e067ce3
Compare
e067ce3 to
23617df
Compare
|
I removed the |
|
cc @OpenAPITools/generator-core-team |
robertschweizer
left a comment
There was a problem hiding this comment.
Thanks a lot for the PR! I checked some of the generated classes.
modules/openapi-generator/src/main/resources/python/requirements.mustache
Show resolved
Hide resolved
| """ | ||
| # data type: List[int] | ||
| oneof_schema_1_validator: Optional[conlist(conint(strict=True, le=255, ge=0), max_items=3, min_items=3)] = Field(None, description="RGB three element array with values 0-255.") | ||
| oneof_schema_1_validator: Optional[Annotated[List[Annotated[int, Field(le=255, strict=True, ge=0)]], Field(min_items=3, max_items=3)]] = Field(default=None, description="RGB three element array with values 0-255.") |
There was a problem hiding this comment.
I do not get an error if I construct this with oneof_schema_1_validator=[1, 2]. Maybe pydantic is thrown off by Field() being used on both sides of =? Also pydantic might not take into account Field() restrictions in the first argument of Annotated[].
Best add a unit-test to make sure validation works, or is there one already?
There was a problem hiding this comment.
I will check this 👍
There was a problem hiding this comment.
I added more tests: this works with Pydantic v2 but not with Pydantic v1. We'll focus on the former anyway and I'll merge my PR in a Pydantic v2-only generator 👍
There was a problem hiding this comment.
This is great, thanks a lot for moving forward to pydantic v2! Then things work of course :)
|
Thanks to the merge of #16643, I have plenty of test failures now :) I will turn this back to draft while I'm fixing the comments and the tests 👍 |
| from pydantic import validate_arguments, ValidationError | ||
| {{#asyncio}} | ||
| from typing import overload, Optional, Union, Awaitable | ||
| {{/asyncio}} |
There was a problem hiding this comment.
2 reasons:
- These imports are not asyncio-specific
- The imported names are not used in the template
The names could be used by the code generated by the Java code, in which case the imports would be provided from the Java code instead.
|
|
||
| // import models one by one | ||
| if (!modelImports.isEmpty()) { | ||
| { |
There was a problem hiding this comment.
I don't remember, I will add it back.
I need to change the place where x-py-model-imports (there could be resources to imports even if there no dependencies between models), I will move it outside the if block.
There was a problem hiding this comment.
I re-added the condition and moved the otherImports.exports() imports out of the block.
| {{/composedSchemas.anyOf}} | ||
| if TYPE_CHECKING: | ||
| actual_instance: Union[{{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}] | ||
| actual_instance: Optional[Union[{{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}]] = None |
There was a problem hiding this comment.
@multani Hi Jonathan! Do you remember, by any chance, why did you introduce Optional here? Is it possible to have None value here even with one_of validator?
There was a problem hiding this comment.
Hey 👋 Sorry, I don't remember the details of this particular change :/ Does it create a problem for you?
There was a problem hiding this comment.
Yes, unfortunately. Before this changes non-optional anyOf had correct typing (Union[A, B]), but now it has additional None in the union, which isn't right and stops me from using proper typing. Should I try to change it back and create PR for it?
There was a problem hiding this comment.
Yes, of course, feel free to create a pull request!
I just checked again, and there's also a is None check in the to_dict method at the end of the file, it's probably why I added the Optional type in the first place. If you remove Optional, can you also remove that check?
In OpenAPITools#16624, I introduced a new mechanism to record imports to other modules, instead of having specialized datetime/typing/pydantic objects to manage imports for these modules. This change reuses the mechanism from OpenAPITools#16624 and replace the specialized import managers by the generic one. Unused imports from various .mustache templates are also cleaned up.
In #16624, I introduced a new mechanism to record imports to other modules, instead of having specialized datetime/typing/pydantic objects to manage imports for these modules. This change reuses the mechanism from #16624 and replace the specialized import managers by the generic one. Unused imports from various .mustache templates are also cleaned up.
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624 (cherry picked from commit d176113)
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624 (cherry picked from commit d176113)
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624 (cherry picked from commit d176113)
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624 (cherry picked from commit d176113630d6b7d4bc36511fe3f8cb013060d675) GitOrigin-RevId: 4e84838785f49f7d0a646018ba22992d82e65a76
Python Client now need pydantic as we use the new version of the OpenAPI python client generator: https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/python/requirements.mustache#L14 It was added in OpenAPITools/openapi-generator#16624 GitOrigin-RevId: d176113630d6b7d4bc36511fe3f8cb013060d675
was:
python: Generate fully described Python typesThe goal of this change is to replace the mypy incompatible types (
conlist,conint,constr, etc.) by their more modern versions usingAnnotatedtypes with Pydantic v2.To do so, the code generator changes in several ways:
PythonTypeis a recursive object that hold the information about a particular type that the generator is trying to buildPydanticType, directly translated from the previousgetPydanticTypemethods, createsPythonTypeinstances from the OpenAPI specifications and produces the final Python types as strings.Importsclass holds all the new Python'simportstatements that the generator produces along the way.Via these new classes, the code generation gets improved by the following:
PythonTypeobjects:getPydanticTypemethods have been unified to remove duplication:OpenAPI type -> Python typetranslation methodCodegenParamererandCodegenPropertyhave been unifiedImportsclass can be passed between calls to accumulate all the imports:References I used to implement the new types:
Annotated: mypy annotation and constrained lists recommendation pydantic/pydantic#975)Related:
Note that this improves only a subset of the code generator, but there are still several places that could be improved:
Importsclass instead of the numerousSetinstances could help to track all the import dependencies, reduce the generated code (and unused imports) and the code generator itself.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)@krjakbrjak as Python tech-comittee
@wing328 as the previous major editor of the code generator