File: versions.py

package info (click to toggle)
python-apischema 0.18.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,636 kB
  • sloc: python: 15,281; makefile: 3; sh: 2
file content (129 lines) | stat: -rw-r--r-- 4,012 bytes parent folder | download | duplicates (2)
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
124
125
126
127
128
129
from dataclasses import dataclass
from typing import Any, Callable, ClassVar, Dict, Optional

from apischema.conversions import Conversion, LazyConversion
from apischema.json_schema.types import JsonSchema, JsonType

RefFactory = Callable[[str], str]


def ref_prefix(prefix: str) -> RefFactory:
    if not prefix.endswith("/"):
        prefix += "/"
    return lambda ref: prefix + ref


def isolate_ref(schema: Dict[str, Any]):
    if "$ref" in schema and len(schema) > 1:
        schema.setdefault("allOf", []).append({"$ref": schema.pop("$ref")})


def to_json_schema_2019_09(schema: JsonSchema) -> Dict[str, Any]:
    result = schema.copy()
    if "prefixItems" in result:
        if "items" in result:
            result["additionalItems"] = result.pop("items")
        result["items"] = result["prefixItems"]
    return result


def to_json_schema_7(schema: JsonSchema) -> Dict[str, Any]:
    result = to_json_schema_2019_09(schema)
    isolate_ref(result)
    if "$defs" in result:
        result["definitions"] = {**result.pop("$defs"), **result.get("definitions", {})}
    if "dependentRequired" in result:
        result["dependencies"] = {
            **result.pop("dependentRequired"),
            **result.get("dependencies", {}),
        }
    return result


OPEN_API_3_0_UNSUPPORTED = [
    "dependentRequired",
    "unevaluatedProperties",
    "additionalItems",
]


def to_open_api_3_0(schema: JsonSchema) -> Dict[str, Any]:
    result = to_json_schema_2019_09(schema)
    for key in OPEN_API_3_0_UNSUPPORTED:
        result.pop(key, ...)
    isolate_ref(result)
    if {"type": "null"} in result.get("anyOf", ()):
        result.setdefault("nullable", True)
        result["anyOf"] = [a for a in result["anyOf"] if a != {"type": "null"}]
    if "type" in result and not isinstance(result["type"], (str, JsonType)):
        if "null" in result["type"]:
            result.setdefault("nullable", True)
        result["type"] = [t for t in result["type"] if t != "null"]
        if len(result["type"]) > 1:
            result.setdefault("anyOf", []).extend(
                {"type": t} for t in result.pop("type")
            )
        else:
            result["type"] = result["type"][0]
    if "examples" in result:
        result.setdefault("example", result.pop("examples")[0])
    if "const" in result:
        result.setdefault("enum", [result.pop("const")])
    return result


@dataclass
class JsonSchemaVersion:
    schema: Optional[str] = None
    ref_prefix: str = ""
    serialization: Optional[Callable] = None
    all_refs: bool = True
    defs: bool = True

    @property
    def conversion(self) -> Optional[Conversion]:
        if self.serialization:
            # Recursive conversion pattern
            tmp = None
            conversion = Conversion(
                self.serialization, sub_conversion=LazyConversion(lambda: tmp)
            )
            tmp = conversion
            return conversion
        else:
            return None

    @property
    def ref_factory(self) -> RefFactory:
        return ref_prefix(self.ref_prefix)

    DRAFT_2020_12: ClassVar["JsonSchemaVersion"]
    DRAFT_2019_09: ClassVar["JsonSchemaVersion"]
    DRAFT_7: ClassVar["JsonSchemaVersion"]
    OPEN_API_3_0: ClassVar["JsonSchemaVersion"]
    OPEN_API_3_1: ClassVar["JsonSchemaVersion"]


JsonSchemaVersion.DRAFT_2020_12 = JsonSchemaVersion(
    "http://json-schema.org/draft/2020-12/schema#", "#/$defs/", None, False, True
)
JsonSchemaVersion.DRAFT_2019_09 = JsonSchemaVersion(
    "http://json-schema.org/draft/2020-12/schema#",
    "#/$defs/",
    to_json_schema_2019_09,
    False,
    True,
)
JsonSchemaVersion.DRAFT_7 = JsonSchemaVersion(
    "http://json-schema.org/draft-07/schema#",
    "#/definitions/",
    to_json_schema_7,
    False,
    True,
)
JsonSchemaVersion.OPEN_API_3_0 = JsonSchemaVersion(
    None, "#/components/schemas/", to_open_api_3_0, True, False
)
JsonSchemaVersion.OPEN_API_3_1 = JsonSchemaVersion(
    None, "#/components/schemas/", None, True, False
)