Skip to content

Commit 15a5d9e

Browse files
committed
show alias
1 parent 50b4a86 commit 15a5d9e

9 files changed

Lines changed: 49 additions & 157 deletions

File tree

docs/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ hide:
5252

5353
### Show as alias
5454

55-
When the extension is configured with `show_as_alias=True`, fields with a `alias` will appear under their alias names in the documentation. This is useful for APIs where the serialized output uses different field names than the Python attribute names. See [Pydantic's alias documentation](https://docs.pydantic.dev/latest/concepts/alias/) for more information.
55+
When the extension is configured with `show_alias=True`, fields with a `alias` will appear under their alias names in the documentation. This is useful for APIs where the serialized output uses different field names than the Python attribute names. See [Pydantic's alias documentation](https://docs.pydantic.dev/latest/concepts/alias/) for more information.
5656

5757
To enable this feature in your documentation configuration, configure the extension as follows:
5858

@@ -63,7 +63,7 @@ plugins:
6363
python:
6464
extensions:
6565
- griffe_pydantic:
66-
show_as_alias: true
66+
show_alias: true
6767
```
6868
6969
Or use the local configuration:
@@ -73,7 +73,7 @@ Or use the local configuration:
7373
options:
7474
extensions:
7575
- griffe_pydantic:
76-
show_as_alias: true
76+
show_alias: true
7777
```
7878
7979
@@ -92,7 +92,7 @@ Or use the local configuration:
9292
options:
9393
heading_level: 4
9494
extensions:
95-
- griffe_pydantic: {show_as_alias: false}
95+
- griffe_pydantic: {show_alias: false}
9696
skip_local_inventory: true
9797
```
9898

@@ -105,7 +105,7 @@ Or use the local configuration:
105105
options:
106106
heading_level: 4
107107
extensions:
108-
- griffe_pydantic: {show_as_alias: true}
108+
- griffe_pydantic: {show_alias: true}
109109
skip_local_inventory: true
110110
```
111111

examples/model_noserialize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
class UserModel(BaseModel):
66
"""A user model with serialization aliases.
77
8-
When the extension is configured with `show_as_alias=True`, fields with
8+
When the extension is configured with `show_alias=True`, fields with
99
`alias` will appear under their alias names in the documentation.
1010
"""
1111

examples/model_serialize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
class UserModel(BaseModel):
55
"""A user model with serialization aliases.
66
7-
When the extension is configured with `show_as_alias=True`, fields with
7+
When the extension is configured with `show_alias=True`, fields with
88
`alias` will appear under their alias names in the documentation.
99
"""
1010

src/griffe_pydantic/_internal/dynamic.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def _process_attribute(
2626
cls: Class,
2727
*,
2828
processed: set[str],
29-
show_as_alias: bool = False,
29+
show_alias: bool = False,
3030
) -> None:
3131
"""Handle Pydantic fields."""
3232
from pydantic.fields import FieldInfo # noqa: PLC0415
@@ -50,7 +50,7 @@ def _process_attribute(
5050
attr.extra[common._self_namespace]["constraints"] = constraints
5151

5252
# Store alias if present
53-
if show_as_alias and obj.alias:
53+
if show_alias and obj.alias:
5454
attr.extra[common._self_namespace]["alias"] = obj.alias
5555
attr.extra[common._mkdocstrings_namespace]["template"] = "pydantic_attribute_alias.html.jinja"
5656

@@ -74,7 +74,7 @@ def _process_class(
7474
*,
7575
processed: set[str],
7676
schema: bool = False,
77-
show_as_alias: bool = False,
77+
show_alias: bool = False,
7878
) -> None:
7979
"""Detect and prepare Pydantic models."""
8080
common._process_class(cls)
@@ -92,7 +92,7 @@ def _process_class(
9292
member, # ty: ignore[invalid-argument-type]
9393
cls,
9494
processed=processed,
95-
show_as_alias=show_as_alias,
95+
show_alias=show_alias,
9696
)
9797
elif kind is Kind.FUNCTION:
9898
_process_function(getattr(obj, member.name), member, cls, processed=processed) # ty: ignore[invalid-argument-type]
@@ -113,5 +113,5 @@ def _process_class(
113113
attr,
114114
cls,
115115
processed=processed,
116-
show_as_alias=show_as_alias,
116+
show_alias=show_alias,
117117
)

src/griffe_pydantic/_internal/extension.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@
2222
class PydanticExtension(Extension):
2323
"""Griffe extension for Pydantic."""
2424

25-
def __init__(self, *, schema: bool = False, show_as_alias: bool = False) -> None:
25+
def __init__(self, *, schema: bool = False, show_alias: bool = False) -> None:
2626
"""Initialize the extension.
2727
2828
Parameters:
2929
schema: Whether to compute and store the JSON schema of models.
30-
show_as_alias: Whether to use `alias` as the field name in documentation.
30+
show_alias: Whether to use `alias` as the field name in documentation.
3131
When enabled, fields with a `alias` will be keyed by that alias instead of their Python attribute name.
3232
"""
3333
super().__init__()
3434
self._schema = schema
35-
self._show_as_alias = show_as_alias
35+
self._show_alias = show_alias
3636
self._processed: set[str] = set()
3737
self._recorded: list[tuple[ObjectNode, Class]] = []
3838

@@ -45,13 +45,13 @@ def on_package(self, *, pkg: Module, **kwargs: Any) -> None: # noqa: ARG002
4545
cls,
4646
processed=self._processed,
4747
schema=self._schema,
48-
show_as_alias=self._show_as_alias,
48+
show_alias=self._show_alias,
4949
)
5050
static._process_module(
5151
pkg,
5252
processed=self._processed,
5353
schema=self._schema,
54-
show_as_alias=self._show_as_alias,
54+
show_alias=self._show_alias,
5555
)
5656

5757
def on_class_instance(self, *, node: ast.AST | ObjectNode, cls: Class, **kwargs: Any) -> None: # noqa: ARG002

src/griffe_pydantic/_internal/static.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def _pydantic_validator(func: Function) -> ExprCall | None:
9696
return None
9797

9898

99-
def _process_attribute(attr: Attribute, cls: Class, *, processed: set[str], show_as_alias: bool = False) -> None:
99+
def _process_attribute(attr: Attribute, cls: Class, *, processed: set[str], show_alias: bool = False) -> None:
100100
"""Handle Pydantic fields."""
101101
if attr.canonical_path in processed:
102102
return
@@ -193,7 +193,7 @@ def _process_attribute(attr: Attribute, cls: Class, *, processed: set[str], show
193193
attr.extra[common._self_namespace]["constraints"] = constraints
194194

195195
# Store alias if present
196-
if show_as_alias and (alias := kwargs.get("alias")):
196+
if show_alias and (alias := kwargs.get("alias")):
197197
if isinstance(alias, str):
198198
try:
199199
attr.extra[common._self_namespace]["alias"] = ast.literal_eval(alias)
@@ -228,7 +228,7 @@ def _process_function(func: Function, cls: Class, *, processed: set[str]) -> Non
228228
common._process_function(func, cls, fields)
229229

230230

231-
def _process_class(cls: Class, *, processed: set[str], schema: bool = False, show_as_alias: bool = False) -> None:
231+
def _process_class(cls: Class, *, processed: set[str], schema: bool = False, show_alias: bool = False) -> None:
232232
"""Finalize the Pydantic model data."""
233233
if cls.canonical_path in processed:
234234
return
@@ -263,19 +263,19 @@ def _process_class(cls: Class, *, processed: set[str], schema: bool = False, sho
263263
for member in cls.all_members.values():
264264
kind = member.kind
265265
if kind is Kind.ATTRIBUTE:
266-
_process_attribute(member, cls, processed=processed, show_as_alias=show_as_alias) # ty: ignore[invalid-argument-type]
266+
_process_attribute(member, cls, processed=processed, show_alias=show_alias) # ty: ignore[invalid-argument-type]
267267
elif kind is Kind.FUNCTION:
268268
_process_function(member, cls, processed=processed) # ty: ignore[invalid-argument-type]
269269
elif kind is Kind.CLASS:
270-
_process_class(member, processed=processed, schema=schema, show_as_alias=show_as_alias) # ty: ignore[invalid-argument-type]
270+
_process_class(member, processed=processed, schema=schema, show_alias=show_alias) # ty: ignore[invalid-argument-type]
271271

272272

273273
def _process_module(
274274
mod: Module,
275275
*,
276276
processed: set[str],
277277
schema: bool = False,
278-
show_as_alias: bool = False,
278+
show_alias: bool = False,
279279
) -> None:
280280
"""Handle Pydantic models in a module."""
281281
if mod.canonical_path in processed:
@@ -285,9 +285,9 @@ def _process_module(
285285
for cls in mod.classes.values():
286286
# Don't process aliases, real classes will be processed at some point anyway.
287287
if not cls.is_alias:
288-
_process_class(cls, processed=processed, schema=schema, show_as_alias=show_as_alias)
288+
_process_class(cls, processed=processed, schema=schema, show_alias=show_alias)
289289

290290
for submodule in mod.modules.values():
291291
# Same for modules, don't process aliased ones.
292292
if not submodule.is_alias:
293-
_process_module(submodule, processed=processed, schema=schema, show_as_alias=show_as_alias)
293+
_process_module(submodule, processed=processed, schema=schema, show_alias=show_alias)
Lines changed: 16 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,19 @@
1-
{#- Template for Python attributes.
1+
{% extends "_base/attribute.html.jinja" %}
22

3-
This template renders a Python attribute (or variable).
4-
This can be a module attribute or a class attribute.
3+
{% block heading %}
4+
{#- Heading block.
55
6-
Context:
7-
attribute (griffe.Attribute): The attribute to render.
8-
root (bool): Whether this is the root object, injected with `:::` in a Markdown page.
9-
heading_level (int): The HTML heading level to use.
10-
config (dict): The configuration options.
11-
-#}
12-
13-
{% block logs scoped %}
14-
{#- Logging block.
15-
16-
This block can be used to log debug messages, deprecation messages, warnings, etc.
6+
This block renders the heading for the attribute.
177
-#}
18-
{{ log.debug("Rendering " + attribute.path) }}
19-
{% endblock logs %}
20-
21-
<div class="doc doc-object doc-attribute">
22-
{% with obj = attribute, html_id = attribute.path %}
23-
24-
{% if root %}
25-
{% set show_full_path = config.show_root_full_path %}
26-
{% set root_members = True %}
27-
{% elif root_members %}
28-
{% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %}
29-
{% set root_members = False %}
30-
{% else %}
31-
{% set show_full_path = config.show_object_full_path %}
32-
{% endif %}
33-
34-
{# {% set attribute_name = attribute.path if show_full_path else attribute.name %} #}
35-
{# TODO some better way to visualize the alias #}
36-
{% set attribute_name = attribute.extra.griffe_pydantic.alias %}
37-
38-
{% if not root or config.show_root_heading %}
39-
{% filter heading(
40-
heading_level,
41-
role="data" if attribute.parent.kind.value == "module" else "attr",
42-
id=html_id,
43-
class="doc doc-heading",
44-
toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-attribute"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else attribute.name),
45-
skip_inventory=config.skip_local_inventory,
46-
) %}
47-
48-
{% block heading scoped %}
49-
{#- Heading block.
50-
51-
This block renders the heading for the attribute.
52-
-#}
53-
{% if config.show_symbol_type_heading %}<code class="doc-symbol doc-symbol-heading doc-symbol-attribute"></code>{% endif %}
54-
{% if config.heading and root %}
55-
{{ config.heading }}
56-
{% elif config.separate_signature %}
57-
<span class="doc doc-object-name doc-attribute-name">{{ attribute_name }}</span>
58-
{% else %}
59-
{%+ filter highlight(language="python", inline=True) %}
60-
{{ attribute_name }}{% if attribute.annotation and config.show_signature_annotations %}: {{ attribute.annotation }}{% endif %}
61-
{% if config.show_attribute_values and attribute.value %} = {{ attribute.value }}{% endif %}
62-
{% endfilter %}
63-
{% endif %}
64-
{% endblock heading %}
65-
66-
{% block labels scoped %}
67-
{#- Labels block.
68-
69-
This block renders the labels for the attribute.
70-
-#}
71-
{% with labels = attribute.labels %}
72-
{% include "labels.html.jinja" with context %}
73-
{% endwith %}
74-
{% endblock labels %}
75-
76-
{% endfilter %}
77-
78-
{% block signature scoped %}
79-
{#- Signature block.
80-
81-
This block renders the signature for the attribute.
82-
-#}
83-
{% if config.separate_signature %}
84-
{% filter format_attribute(attribute, config.line_length, crossrefs=config.signature_crossrefs, show_value=config.show_attribute_values) %}
85-
{{ attribute.name }}
86-
{% endfilter %}
87-
{% endif %}
88-
{% endblock signature %}
89-
90-
{% else %}
91-
92-
{% if config.show_root_toc_entry %}
93-
{% filter heading(heading_level,
94-
role="data" if attribute.parent.kind.value == "module" else "attr",
95-
id=html_id,
96-
toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-attribute"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else attribute_name),
97-
hidden=True,
98-
skip_inventory=config.skip_local_inventory,
99-
) %}
100-
{% endfilter %}
101-
{% endif %}
102-
{% set heading_level = heading_level - 1 %}
103-
{% endif %}
104-
105-
<div class="doc doc-contents {% if root %}first{% endif %}">
106-
{% block contents scoped %}
107-
{#- Contents block.
108-
109-
This block renders the contents of the attribute.
110-
It contains other blocks that users can override.
111-
Overriding the contents block allows to rearrange the order of the blocks.
112-
-#}
113-
{% block docstring scoped %}
114-
{#- Docstring block.
115-
116-
This block renders the docstring for the attribute.
117-
-#}
118-
{% with docstring_sections = attribute.docstring.parsed %}
119-
{% include "docstring.html.jinja" with context %}
120-
{% endwith %}
121-
{% endblock docstring %}
122-
123-
{% if config.backlinks %}
124-
<backlinks identifier="{{ html_id }}" handler="python" />
125-
{% endif %}
126-
{% endblock contents %}
127-
</div>
128-
129-
{% endwith %}
130-
</div>
8+
{% if config.show_symbol_type_heading %}<code class="doc-symbol doc-symbol-heading doc-symbol-attribute"></code>{% endif %}
9+
{% if config.heading and root %}
10+
{{ config.heading }}
11+
{% elif config.separate_signature %}
12+
<span class="doc doc-object-name doc-attribute-name">{{ attribute_name }} ({{ attribute.extra.griffe_pydantic.alias }})</span>
13+
{% else %}
14+
{%+ filter highlight(language="python", inline=True) %}
15+
{{ attribute_name }}{% if attribute.annotation and config.show_signature_annotations %}: {{ attribute.annotation }}{% endif %}
16+
{% if config.show_attribute_values and attribute.value %} = {{ attribute.value }}{% endif %}
17+
{% endfilter %}
18+
{% endif %}
19+
{% endblock heading %}

src/griffe_pydantic/templates/material/_base/pydantic_model.html.jinja

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</details>
1212
{% endif %}
1313
{% endblock schema %}
14-
14+
1515
{% block config scoped %}
1616
{% if class.extra.griffe_pydantic.config %}
1717
<p>Config:</p>
@@ -31,6 +31,9 @@
3131
{% for name, field in fields.items() %}
3232
<li>
3333
<code><autoref optional hover identifier="{{ field.path }}">{{ name }}</autoref></code>
34+
{% if field.extra.griffe_pydantic.alias %}
35+
(<code><em>{{ field.extra.griffe_pydantic.alias }}</em></code>)
36+
{% endif %}
3437
{% with expression = field.annotation %}
3538
(<code>{% include "expression.html.jinja" with context %}</code>)
3639
{% endwith %}

tests/test_extension.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def test_extension(analysis: str) -> None:
6969
with loader(
7070
"package",
7171
modules={"__init__.py": code},
72-
extensions=Extensions(PydanticExtension(schema=True, show_as_alias=True)),
72+
extensions=Extensions(PydanticExtension(schema=True, show_alias=True)),
7373
search_sys_path=analysis == "dynamic",
7474
) as package:
7575
assert package
@@ -401,8 +401,8 @@ class Model(BaseModel):
401401
assert "With multiple lines." in package["Model.field1"].docstring.value
402402

403403

404-
def test_show_as_alias_disabled_static() -> None:
405-
"""Test that without show_as_alias, static analysis uses Python attribute names."""
404+
def test_show_alias_disabled_static() -> None:
405+
"""Test that without show_alias, static analysis uses Python attribute names."""
406406
code = """
407407
from pydantic import BaseModel, Field
408408
@@ -413,7 +413,7 @@ class Model(BaseModel):
413413
with temporary_visited_package(
414414
"package",
415415
modules={"__init__.py": code},
416-
extensions=Extensions(PydanticExtension(schema=False, show_as_alias=False)),
416+
extensions=Extensions(PydanticExtension(schema=False, show_alias=False)),
417417
) as package:
418418
fields = package["Model"].extra["griffe_pydantic"]["fields"]()
419419
assert "internal_name" in fields

0 commit comments

Comments
 (0)