datamodel-code-generator
datamodel-code-generator copied to clipboard
Improve `mypy` hinting on `RootModel` with `oneOf`
First of all, thank you for this project! It's been invaluable in a few of my libraries.
Is your feature request related to a problem? Please describe.
Per https://github.com/koxudaxi/datamodel-code-generator/issues/1779 and similar issues, datamodel-codegen
currently produces unified oneOf
types using RootModel
as a base class, e.g.:
class Foo(RootModel[Union[Bar, Baz]]):
root: Union[Bar, Baz]
This is semantically correct and supported by Pydantic. However, as noted in https://github.com/pydantic/pydantic/discussions/7418, some typecheckers (like mypy
) struggle with this format.
For Python 3.8+, Pydantic recommends this form instead:
Foo = RootModel[Union[Bar, Baz]]
...which mypy
does understand, and is able to infer Foo(...)
's params/kwargs for.
Describe the solution you'd like
When --target-python-version
is 3.8
or newer, datamodel-codegen
should emit (or be able to be configured to emit) the RootModel[...]
annotation format, rather than the inheritance format.
Describe alternatives you've considered
I could just bushwack around this in my codebases by ignoring the mypy
errors. But it'd be nice to have a generalized fix upstream here 😅
Additional context
N/A
For a concrete example of this failing, see this CI job.
This happens because of a generated type that looks like this:
class DsseSchema(RootModel[Union[DsseV001Schema1, DsseV001Schema2]]):
model_config = ConfigDict(
populate_by_name=True,
)
root: Union[DsseV001Schema1, DsseV001Schema2] = Field(
...,
description="log entry schema for dsse envelopes",
title="DSSE Schema",
)
...which then gets instantiated like this:
proposed_entry = rekor_types.Dsse(
spec=rekor_types.dsse.DsseSchema(
proposed_content=rekor_types.dsse.ProposedContent(
envelope=content.to_json(),
verifiers=[b64_cert.decode()],
),
),
)
...which fails, since Dsse
's constructor is not inferred to be the superset of DsseV001Schema1 | DsseV001Schema2
.
@woodruffw Thank you for exploring the solution. Is your error related to the issue? https://github.com/koxudaxi/datamodel-code-generator/issues/1921
I would like to know, if you know, if your solution is version-constrained on the Pydantic side? Can it be used with 2.5, etc.?
Thanks for your response @koxudaxi! #1921 looks like a different issue -- in my case the generated code is syntactically and semantically sound, but just doesn't work with the patterns mypy
and Pydantic both understand for kwarg
inference 🙂
I would like to know, if you know, if your solution is version-constrained on the Pydantic side? Can it be used with 2.5, etc.?
Yes, I believe it can be used with anything in 2.x!
Thanks for the bug report @woodruffw - I am also running into this issue.