Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/griffe_pydantic/_internal/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

_logger = get_logger("griffe_pydantic")

_ANNOTATED_PATHS = {"typing.Annotated", "typing_extensions.Annotated"}


def _extract_description(description: Expr | str) -> str | None:
"""Extract a description value from a Field argument.
Expand Down Expand Up @@ -122,7 +124,7 @@ def _process_attribute(attr: Attribute, cls: Class, *, processed: set[str]) -> N
field_call = None
if (
isinstance(attr.annotation, ExprSubscript)
and attr.annotation.canonical_path == "typing.Annotated"
and attr.annotation.canonical_path in _ANNOTATED_PATHS
and isinstance(attr.annotation.slice, ExprTuple)
):
# Extract Field from Annotated's slice elements
Expand Down
26 changes: 26 additions & 0 deletions tests/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,29 @@ class Model(BaseModel):
assert package["Model.field1"].docstring is not None
assert "This is a multiline description." in package["Model.field1"].docstring.value
assert "With multiple lines." in package["Model.field1"].docstring.value


def test_typing_extensions_annotated_fields() -> None:
"""Test the extension with fields annotated through `typing_extensions`."""
code = """
from pydantic import BaseModel, Field
import typing_extensions as te

class Model(BaseModel):
a: te.Annotated[int, Field(description="Some description.", le=10)]
b: te.Annotated[int, Field(description="Another description.")] = 1
"""
with temporary_visited_package(
"package",
modules={"__init__.py": code},
extensions=Extensions(PydanticExtension(schema=False)),
) as package:
assert "pydantic-field" in package["Model.a"].labels
assert "pydantic-field" in package["Model.b"].labels
assert package["Model.a"].docstring.value == "Some description."
assert package["Model.b"].docstring.value == "Another description."
# The `Annotated` wrapper is unwrapped, leaving the actual type.
assert str(package["Model.a"].annotation) == "int"
assert str(package["Model.b"].annotation) == "int"
# Constraints declared inside `Annotated` are collected too.
assert package["Model.a"].extra["griffe_pydantic"]["constraints"] == {"le": "10"}
Loading