Skip to content

feat: serialize on alias#56

Open
watermarkhu wants to merge 19 commits intomkdocstrings:mainfrom
watermarkhu:feat-alias
Open

feat: serialize on alias#56
watermarkhu wants to merge 19 commits intomkdocstrings:mainfrom
watermarkhu:feat-alias

Conversation

@watermarkhu
Copy link
Copy Markdown

For reviewers

  • I did not use AI
  • I used AI and thoroughly reviewed every code/docs change

Description of the change

For documentation purpose, it might be helpful to serialize the documented model on the alias. I've opted for the serialization_alias field property, which should map what the output field name of the model should be.

Originally, I was using the model config value serialize_by_alias to detect whether a field name should be serialized by the alias in the documentation. But eventually, it seemed more logical to put it as a extension config item instead, separating the model output alias serialization and the documentation field alias serialization.

Relevant resources

@watermarkhu
Copy link
Copy Markdown
Author

@pawamoy All the test fail on 3.15 but I guess that's known?

@pawamoy
Copy link
Copy Markdown
Member

pawamoy commented Mar 3, 2026

@watermarkhu thanks for the PR 🙂

Yes tests on 3.15 are allowed to fail.

I see a few style changes related to line length, could you revert those?

Copy link
Copy Markdown
Member

@pawamoy pawamoy left a comment

Choose a reason for hiding this comment

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

Could you explain how Pydantic models and instances behaves with serialization aliases? Can you still access the attributes with the original name, and with the alias name? Or just with the alias name?

@pawamoy
Copy link
Copy Markdown
Member

pawamoy commented Mar 3, 2026

But eventually, it seemed more logical to put it as a extension config item instead, separating the model output alias serialization and the documentation field alias serialization.

Then shouldn't we avoid re-assigning attribute names, and display the aliased names via the custom template provided by the extension instead?

@watermarkhu
Copy link
Copy Markdown
Author

@pawamoy I've refactored it now to not hijack the key-mapping of the attributes, but to forward the attribute to use an attribute template that comes with griffe-pydantic, similar how it's done for the class. How the template is formatted is still up for debate, and is marked as TODO.

Do you agree with this direction?

@watermarkhu
Copy link
Copy Markdown
Author

Could you explain how Pydantic models and instances behaves with serialization aliases? Can you still access the attributes with the original name, and with the alias name? Or just with the alias name?

In Pydantic there is now the distinction between alias, which covers both input and output, and validation_alias and serialization_alias that cover input and output, respectively.

My argument for only looking at the serialization_alias is that it explicitly sets what the model should export to, but that is perhaps a bit shortsighted and we should look at the alias as well.

The main thing is that the documentation should reflect how a client would interact with the model. The aliases are typically a way to represent attributes in a more human way, compared to the typically snake_case attribute names. So it should be presented more front and center when documented via mkdocstrings and griffe-pydantic. Any opinions?

@pawamoy
Copy link
Copy Markdown
Member

pawamoy commented Mar 11, 2026

The main thing is that the documentation should reflect how a client would interact with the model.

I see two things here.

  1. How your internal (or maybe public) API is used. For this we would display the actual attribute names, not aliases.
  2. How potential clients of your API send/pass input data (or receive output data for that matter). For this we should display alias names. But for all we know, clients may not use your own Pydantic models (or even Python at all).

I believe it's best to display both at once. Actual attribute names, for regular API use, and both input and output alias names, for potential clients. Let me check the new template 🙂

@pawamoy
Copy link
Copy Markdown
Member

pawamoy commented Mar 11, 2026

OK so I feel like the best thing to do here is:

  • collect alias info in extra data (both validation and serialization aliases)
  • provide a pydantic field template (as you did here) that displays those in addition to the regular stuff

Have a look at the template for models: it inherits parent blocks from the class template. We should do the same for the field template: it should inherit from the attribute template. This way it's automatically kept in sync with upstream changes (and it will be much lighter).

@pawamoy
Copy link
Copy Markdown
Member

pawamoy commented Mar 12, 2026

Thanks, it's starting to be in good shape 🚀! I figured we could by default always show aliases: that's what the extension is for, showing Pydantic stuff with all the relevant info, so I don't think we need a flag here 🙂

I also figured we could always render fields with the field template.

I'll push changes that reflect that.

Comment on lines +85 to +96
# Process model fields that may not have been discovered by griffe
if hasattr(obj, "model_fields") and isinstance(obj.model_fields, dict):
for field_name, field_info in obj.model_fields.items():
if field_name not in cls.all_members:
# Create an Attribute object for this field
attr = Attribute(
name=field_name,
lineno=0,
endlineno=0,
)
cls.members[field_name] = attr # ty: ignore[invalid-assignment]
_process_attribute(field_info, attr, cls, processed=processed)
Copy link
Copy Markdown
Member

@pawamoy pawamoy Mar 12, 2026

Choose a reason for hiding this comment

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

Can you explain why we need this? This sounds like something we should potentially add in a separate PR before merging this one.

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.

I think I had some issues with the fields showing up during the dynamic search. But I think I was still struggling with the logic from common. It is indeed not needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If it's not needed, can we remove it?

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.

So actually, we do need them. During dynamic analysis or search_sys_path=True, the model fields are not showing up in all_members. I've added a test in dc535b1 to check the model fields of a previously existing test class.

@watermarkhu
Copy link
Copy Markdown
Author

watermarkhu commented Mar 15, 2026

Indeed, always showing the alias should be the behavior. I was still fixed on having the option because it replaced the shown field initially.

I've made a final(?) edit that just shows the alias if the serialization alias and validation alias are the same. This corresponds with the field argument logic in Pydantic 😄

Sign up for free to 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.

2 participants