Skip to content

Commit c83074d

Browse files
committed
feat: Also support pydantic.model_validator
Issue-4: #4
1 parent 3e1020e commit c83074d

File tree

3 files changed

+21
-9
lines changed

3 files changed

+21
-9
lines changed

docs/examples/model_ext.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from pydantic import field_validator, ConfigDict, BaseModel, Field
1+
from typing import Any
2+
from pydantic import field_validator, model_validator, ConfigDict, BaseModel, Field
23

34

45
class ExampleModel(BaseModel):
@@ -26,3 +27,11 @@ def check_max_length_ten(cls, v) -> str:
2627
if len(v) >= 10:
2728
raise ValueError("No more than 10 characters allowed")
2829
return v
30+
31+
@model_validator(mode="before")
32+
@classmethod
33+
def lowercase_only(cls, data: dict[str, Any]) -> dict[str, Any]:
34+
"""Ensure that the field without a default is lowercase."""
35+
if isinstance(data.get("field_without_default"), str):
36+
data["field_without_default"] = data["field_without_default"].lower()
37+
return data

src/griffe_pydantic/static.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def inherits_pydantic(cls: Class) -> bool:
4848
return any(inherits_pydantic(parent_class) for parent_class in cls.mro())
4949

5050

51-
def pydantic_field_validator(func: Function) -> ExprCall | None:
51+
def pydantic_validator(func: Function) -> ExprCall | None:
5252
"""Return a function's `pydantic.field_validator` decorator if it exists.
5353
5454
Parameters:
@@ -58,7 +58,7 @@ def pydantic_field_validator(func: Function) -> ExprCall | None:
5858
A decorator value (Griffe expression).
5959
"""
6060
for decorator in func.decorators:
61-
if isinstance(decorator.value, ExprCall) and decorator.callable_path == "pydantic.field_validator":
61+
if isinstance(decorator.value, ExprCall) and decorator.callable_path in {"pydantic.field_validator", "pydantic.model_validator"}:
6262
return decorator.value
6363
return None
6464

@@ -110,7 +110,7 @@ def process_function(func: Function, cls: Class, *, processed: set[str]) -> None
110110
logger.warning(f"cannot yet process {func}")
111111
return
112112

113-
if decorator := pydantic_field_validator(func):
113+
if decorator := pydantic_validator(func):
114114
fields = [ast.literal_eval(field) for field in decorator.arguments if isinstance(field, str)]
115115
common.process_function(func, cls, fields)
116116

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

+8-5
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,14 @@
4848
<ul>
4949
{% for name, validator in validators.items() %}
5050
<li>
51-
<code><autoref optional hover identifier="{{ validator.path }}">{{ name }}</autoref></code> &rarr;
52-
{% for target in validator.extra.griffe_pydantic.targets %}
53-
<code><autoref optional hover identifier="{{ target.path }}">{{ target.name }}</autoref></code>
54-
{%- if not loop.last %}, {% endif %}
55-
{% endfor %}
51+
<code><autoref optional hover identifier="{{ validator.path }}">{{ name }}</autoref></code>
52+
{% if validator.extra.griffe_pydantic.targets %}
53+
&rarr;
54+
{% for target in validator.extra.griffe_pydantic.targets %}
55+
<code><autoref optional hover identifier="{{ target.path }}">{{ target.name }}</autoref></code>
56+
{%- if not loop.last %}, {% endif %}
57+
{% endfor %}
58+
{% endif %}
5659
</li>
5760
{% endfor %}
5861
</ul>

0 commit comments

Comments
 (0)