Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[PoC] Add support forpydantic models viadatamodel-code-generator#1049

felixatmaltego started this conversation inFeature request
Discussion options

Hi!

I really like this library and use it for all my clients. Unfortunately, I usepydantic in myFastAPI projects. Convertingattrs topydantic models is possible, but a bit cumbersome. Instead, I found an easy way to use pydantic models withopenapi-python-client.

Whileopenapi-python-client generatesattrs models with custom parser logic, it is nicer for me to usepydantic as in the
rest of myFastAPI projects. Therefore, we generate the models withdatamodel-code-generator, and the client logic
withopenapi-python-client.

To make this possible, only two important changes are necessary:

  • useBaseModel::model_validate(...) instead of the customfrom_dict(...) method generated
    byopenapi-python-client
  • change the imports fromfrom ...models.<model-dir> import <Model> tofrom ...models import <Model>,
    becausedatamodel-code-generator creates a flat file

templates/property_templates/model_property.py.jinja

--- model_property.py.original.jinja2024-06-06 17:54:48+++ model_property.py.jinja2024-06-06 19:07:31@@ -1,5 +1,5 @@ {% macro construct_function(property, source) %}-{{ property.class_info.name }}.from_dict({{ source }})+{{ property.class_info.name }}.model_validate({{ source }}) {% endmacro %}  {% from "property_templates/property_macros.py.jinja" import construct_template %}

templates/endpoint_module.py.jinja

--- endpoint_module.py.original.jinja2024-06-06 17:45:47+++ endpoint_module.py.jinja2024-06-06 18:25:13@@ -3,12 +3,22 @@  import httpx+{% macro transform_import(original_string) -%}+    {%- if original_string.startswith('from ...models') -%}+        {%- set parts = original_string.split(' ') -%}+        {%- set new_string = 'from ...models import ' + parts[3] -%}+        {{ new_string }}+    {%- else -%}+        {{ original_string }}+    {%- endif -%}+{%- endmacro %}+ from ...client import AuthenticatedClient, Client from ...types import Response, UNSET from ... import errors  {% for relative in endpoint.relative_imports %}-{{ relative }}+{{ transform_import(relative) }} {% endfor %}  {% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params,

To generate our modified client, we have to:

  • generate the client as normal
  • delete all files inopenapi-client/openapi_client/models/*
  • generate ourpydantic models toopenapi-client/openapi_client/models/__init__.py

I created a small shell script to do this

# openapi-python-client generate --path openapi.json --custom-template-path=templatesopenapi-python-client update --path openapi.json --custom-template-path=templatesrm -r openapi-client/openapi_client/models/*datamodel-codegen --input openapi.json \  --output-model-type pydantic_v2.BaseModel \  --strict-nullable --snake-case-field --capitalize-enum-members \  --use-union-operator --use-standard-collections \> openapi-client/openapi_client/models/__init__.py

The--strict-nullable --snake-case-field --capitalize-enum-members flags were necessary to be equivalent to theattrs models.

Another thing is thatopenapi-python-client suffixes reserved names with an '_'. I had to change those occurences.
Apart from that, the resulting code is compatible with theattrs models.

Hope this helps someone. Would be amazing to see this as a feature!

You must be logged in to vote

Replies: 3 comments 1 reply

Comment options

Yes wondering why thepydantic models are not used by default maybe there's some reason to make it more general purpose. Ran into this when using some endpoints that are pass through and was hoping to reuse the model that was generated.

But like you mentioned an option to choose to generate the pydantic models would be great.

You must be logged in to vote
0 replies
Comment options

This was a very helpful post, thanks@felixatmaltego!

I found I had to monkey patch the pydanticBaseModel to get the generated client to work:

def dump_dict(self):    return self.model_dump()# Apply the monkey-patchBaseModel.to_dict = dump_dict

Otherwise it fails at the line:

def _get_kwargs)...       _body = body.to_dict() # fails here
You must be logged in to vote
1 reply
@jboreiko
Comment options

this should help alleviate the issue you mention above - I would also note I choosemode="json" to avoid serialisation issues in the httpx client, andby_alias=True to ensure--snake-case-field conversions don't cause improperly serialised fields.

--- a/openapi_python_client/templates/property_templates/model_property.py.jinja+++ b/openapi_python_client/templates/property_templates/model_property.py.jinja@@ -11,7 +11,7 @@ {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, dict){% endmacro %}  {% macro transform(property, source, destination, declare_type=True) %}-{% set transformed = source + ".to_dict()" %}+{% set transformed = source + ".model_dump(mode=\"json\", by_alias=True)" %} {% set type_string = property.get_type_string(json=True) %} {% if property.required %} {{ destination }} = {{ transformed }}
Comment options

Seconding this feature, this capability would be a huge help! It would be nice if this was an extra flag that could be passed into the client generation script.

You must be logged in to vote
0 replies
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Labels
None yet
5 participants
@felixatmaltego@markns@jboreiko@msimbirsky@JoeGaffney

[8]ページ先頭

©2009-2025 Movatter.jp