File: test_refs.py

package info (click to toggle)
python-apischema 0.18.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,624 kB
  • sloc: python: 15,266; sh: 7; makefile: 7
file content (123 lines) | stat: -rw-r--r-- 3,142 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
113
114
115
116
117
118
119
120
121
122
123
from dataclasses import dataclass
from typing import Collection, Generic, List, Optional, Sequence, TypeVar

import pytest
from pytest import raises

from apischema import settings, type_name
from apischema.conversions import Conversion, LazyConversion
from apischema.json_schema import deserialization_schema, serialization_schema
from apischema.json_schema.schema import DeserializationSchemaBuilder
from apischema.type_names import get_type_name
from apischema.typing import Annotated


@type_name(None)
@dataclass
class A:
    a: int


@dataclass
class B:
    a: Optional[A]


type_name("Bs")(List[B])


@type_name("DD")
@dataclass
class D:
    bs: Annotated[List[B], type_name("Bs2")]  # noqa: F821


@dataclass
class Recursive:
    rec: Optional["Recursive"]


def test_find_refs():
    refs: dict = {}
    DeserializationSchemaBuilder.RefsExtractor(
        settings.deserialization.default_conversion, refs
    ).visit(D)
    DeserializationSchemaBuilder.RefsExtractor(
        settings.deserialization.default_conversion, refs
    ).visit(Recursive)
    assert refs == {
        "B": (B, 1),
        "DD": (D, 1),
        "Bs": (Collection[B], 1),
        "Bs2": (Annotated[List[B], type_name("Bs2")], 1),
        "Recursive": (Recursive, 2),
    }


T = TypeVar("T")
U = TypeVar("U")


@dataclass
class DataGeneric(Generic[T]):
    a: T


type_name("StrData")(DataGeneric[str])


@pytest.mark.parametrize("cls", [DataGeneric, DataGeneric[U]])  # type: ignore
def test_generic_ref_error(cls):
    with raises(TypeError):
        type_name("Data")(cls)


def test_generic_schema():
    assert deserialization_schema(DataGeneric, all_refs=True) == {
        "$schema": "http://json-schema.org/draft/2020-12/schema#",
        "type": "object",
        "properties": {"a": {}},
        "required": ["a"],
        "additionalProperties": False,
    }
    assert deserialization_schema(DataGeneric[int], all_refs=True) == {
        "$schema": "http://json-schema.org/draft/2020-12/schema#",
        "type": "object",
        "properties": {"a": {"type": "integer"}},
        "required": ["a"],
        "additionalProperties": False,
    }
    assert deserialization_schema(DataGeneric[str], all_refs=True) == {
        "$schema": "http://json-schema.org/draft/2020-12/schema#",
        "$ref": "#/$defs/StrData",
        "$defs": {
            "StrData": {
                "type": "object",
                "properties": {"a": {"type": "string"}},
                "required": ["a"],
                "additionalProperties": False,
            }
        },
    }


def test_collection_type_name():
    type_name("test")(Sequence[A])
    assert get_type_name(List[A]) == get_type_name(Collection[A]) == ("test", "test")


@type_name(None)
class RecConv:
    pass


def rec_converter(rec: RecConv) -> List[RecConv]:  # type: ignore
    ...


def test_recursive_conversion_without_ref():
    tmp = None
    conversion = Conversion(rec_converter, sub_conversion=LazyConversion(lambda: tmp))
    tmp = conversion
    with raises(TypeError, match=r"Recursive type <.*> needs a ref.*"):
        serialization_schema(RecConv, conversion=conversion)