Coverage for src/griffe_pydantic/dynamic.py: 23.08%
27 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-18 01:11 +0100
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-18 01:11 +0100
1"""Griffe extension for Pydantic."""
3from __future__ import annotations
5from typing import TYPE_CHECKING
7from griffe import (
8 Attribute,
9 Class,
10 Docstring,
11 Function,
12 get_logger,
13)
14from pydantic.fields import FieldInfo
16from griffe_pydantic import common
18if TYPE_CHECKING:
19 from griffe import ObjectNode
21logger = get_logger(__name__)
24def process_attribute(node: ObjectNode, attr: Attribute, cls: Class) -> None:
25 """Handle Pydantic fields."""
26 if attr.name == "model_config":
27 cls.extra[common.self_namespace]["config"] = node.obj
28 return
30 if not isinstance(node.obj, FieldInfo):
31 return
33 attr.labels = {"pydantic-field"}
34 attr.value = node.obj.default
35 constraints = {}
36 for constraint in common.field_constraints:
37 if (value := getattr(node.obj, constraint, None)) is not None:
38 constraints[constraint] = value
39 attr.extra[common.self_namespace]["constraints"] = constraints
41 # Populate docstring from the field's `description` argument.
42 if not attr.docstring and (docstring := node.obj.description):
43 attr.docstring = Docstring(docstring, parent=attr)
46def process_function(node: ObjectNode, func: Function, cls: Class) -> None:
47 """Handle Pydantic field validators."""
48 if dec_info := getattr(node.obj, "decorator_info", None):
49 common.process_function(func, cls, dec_info.fields)
52def process_class(node: ObjectNode, cls: Class) -> None:
53 """Detect and prepare Pydantic models."""
54 common.process_class(cls)
55 cls.extra[common.self_namespace]["schema"] = common.json_schema(node.obj)