File: test_deferred_annotations.py

package info (click to toggle)
pydantic 2.12.5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,640 kB
  • sloc: python: 75,984; javascript: 181; makefile: 115; sh: 38
file content (112 lines) | stat: -rw-r--r-- 2,494 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""Tests related to deferred evaluation of annotations introduced in Python 3.14 by PEP 649 and 749."""

import sys
from dataclasses import field
from typing import Annotated

import pytest
from annotated_types import MaxLen

from pydantic import (
    BaseModel,
    Field,
    ValidationError,
    field_serializer,
    field_validator,
    model_serializer,
    model_validator,
)
from pydantic.dataclasses import dataclass

pytestmark = pytest.mark.skipif(
    sys.version_info < (3, 14), reason='Requires deferred evaluation of annotations introduced in Python 3.14'
)


def test_deferred_annotations_model() -> None:
    class Model(BaseModel):
        a: Int
        b: Str = 'a'

    Int = int
    Str = str

    inst = Model(a='1', b=b'test')
    assert inst.a == 1
    assert inst.b == 'test'


def test_deferred_annotations_nested_model() -> None:
    def outer():
        def inner():
            class Model(BaseModel):
                ann: Annotated[List[Dict[str, str]], MaxLen(1)]

            Dict = dict

            return Model

        List = list

        Model = inner()

        return Model

    Model = outer()

    with pytest.raises(ValidationError) as exc_info:
        Model(ann=[{'a': 'b'}, {'c': 'd'}])

    assert exc_info.value.errors()[0]['type'] == 'too_long'


def test_deferred_annotations_pydantic_dataclass() -> None:
    @dataclass
    class A:
        a: Int = field(default=1)

    Int = int

    assert A(a='1').a == 1


def test_deferred_annotations_pydantic_dataclass_pydantic_field() -> None:
    """When initial support for Python 3.14 was added, this failed as support for the Pydantic
    `Field()` function was implemented by writing directly to `__annotations__`.
    """

    @dataclass
    class A:
        a: Int = Field(default=1)

    Int = int

    assert A(a='1').a == 1


def test_deferred_annotations_return_values() -> None:
    class Model(BaseModel):
        a: int

        @model_validator(mode='after')
        def check(self) -> Model:
            return self

        @model_validator(mode='before')
        def before(cls, data) -> MyDict:
            return data

        @model_serializer(mode='plain')
        def ser(self) -> MyDict:
            return {'a': self.a}

        @field_validator('a', mode='before')
        def validate_a(cls, v) -> MyInt:
            return v

        @field_serializer('a', mode='plain')
        def serialize_a(self, v) -> MyInt:
            return v

    MyDict = dict
    MyInt = int