datamodel-code-generator 0.27.2__py3-none-any.whl → 0.28.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of datamodel-code-generator might be problematic. Click here for more details.
- datamodel_code_generator/__init__.py +168 -196
- datamodel_code_generator/__main__.py +146 -189
- datamodel_code_generator/arguments.py +227 -230
- datamodel_code_generator/format.py +77 -129
- datamodel_code_generator/http.py +12 -10
- datamodel_code_generator/imports.py +59 -65
- datamodel_code_generator/model/__init__.py +28 -31
- datamodel_code_generator/model/base.py +100 -144
- datamodel_code_generator/model/dataclass.py +62 -70
- datamodel_code_generator/model/enum.py +34 -30
- datamodel_code_generator/model/imports.py +13 -11
- datamodel_code_generator/model/msgspec.py +116 -138
- datamodel_code_generator/model/pydantic/__init__.py +18 -28
- datamodel_code_generator/model/pydantic/base_model.py +121 -140
- datamodel_code_generator/model/pydantic/custom_root_type.py +2 -2
- datamodel_code_generator/model/pydantic/dataclass.py +6 -4
- datamodel_code_generator/model/pydantic/imports.py +35 -33
- datamodel_code_generator/model/pydantic/types.py +91 -119
- datamodel_code_generator/model/pydantic_v2/__init__.py +21 -18
- datamodel_code_generator/model/pydantic_v2/base_model.py +118 -127
- datamodel_code_generator/model/pydantic_v2/imports.py +5 -3
- datamodel_code_generator/model/pydantic_v2/root_model.py +6 -6
- datamodel_code_generator/model/pydantic_v2/types.py +11 -7
- datamodel_code_generator/model/rootmodel.py +1 -1
- datamodel_code_generator/model/scalar.py +33 -32
- datamodel_code_generator/model/typed_dict.py +41 -51
- datamodel_code_generator/model/types.py +24 -19
- datamodel_code_generator/model/union.py +21 -17
- datamodel_code_generator/parser/__init__.py +16 -12
- datamodel_code_generator/parser/base.py +327 -515
- datamodel_code_generator/parser/graphql.py +87 -119
- datamodel_code_generator/parser/jsonschema.py +438 -607
- datamodel_code_generator/parser/openapi.py +180 -220
- datamodel_code_generator/pydantic_patch.py +8 -9
- datamodel_code_generator/reference.py +199 -297
- datamodel_code_generator/types.py +149 -215
- datamodel_code_generator/util.py +23 -36
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/METADATA +10 -5
- datamodel_code_generator-0.28.0.dist-info/RECORD +59 -0
- datamodel_code_generator-0.27.2.dist-info/RECORD +0 -59
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/WHEEL +0 -0
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/entry_points.txt +0 -0
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,27 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
import enum as _enum
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
from contextlib import contextmanager
|
|
6
|
-
from functools import lru_cache
|
|
6
|
+
from functools import cached_property, lru_cache
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import
|
|
9
|
-
TYPE_CHECKING,
|
|
10
|
-
Any,
|
|
11
|
-
Callable,
|
|
12
|
-
ClassVar,
|
|
13
|
-
DefaultDict,
|
|
14
|
-
Dict,
|
|
15
|
-
Generator,
|
|
16
|
-
Iterable,
|
|
17
|
-
Iterator,
|
|
18
|
-
List,
|
|
19
|
-
Mapping,
|
|
20
|
-
Optional,
|
|
21
|
-
Sequence,
|
|
22
|
-
Set,
|
|
23
|
-
Tuple,
|
|
24
|
-
Type,
|
|
25
|
-
Union,
|
|
26
|
-
)
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Optional, Union
|
|
27
9
|
from urllib.parse import ParseResult
|
|
28
10
|
from warnings import warn
|
|
29
11
|
|
|
@@ -37,7 +19,7 @@ from datamodel_code_generator import (
|
|
|
37
19
|
load_yaml_from_path,
|
|
38
20
|
snooper_to_methods,
|
|
39
21
|
)
|
|
40
|
-
from datamodel_code_generator.format import PythonVersion
|
|
22
|
+
from datamodel_code_generator.format import PythonVersion, PythonVersionMin
|
|
41
23
|
from datamodel_code_generator.model import DataModel, DataModelFieldBase
|
|
42
24
|
from datamodel_code_generator.model import pydantic as pydantic_model
|
|
43
25
|
from datamodel_code_generator.model.base import UNDEFINED, get_module_name
|
|
@@ -63,7 +45,6 @@ from datamodel_code_generator.types import (
|
|
|
63
45
|
from datamodel_code_generator.util import (
|
|
64
46
|
PYDANTIC_V2,
|
|
65
47
|
BaseModel,
|
|
66
|
-
cached_property,
|
|
67
48
|
field_validator,
|
|
68
49
|
model_validator,
|
|
69
50
|
)
|
|
@@ -73,89 +54,88 @@ if PYDANTIC_V2:
|
|
|
73
54
|
|
|
74
55
|
from datamodel_code_generator.format import DatetimeClassType
|
|
75
56
|
|
|
57
|
+
if TYPE_CHECKING:
|
|
58
|
+
from collections.abc import Generator, Iterable, Iterator, Mapping, Sequence
|
|
59
|
+
|
|
76
60
|
|
|
77
|
-
def get_model_by_path(
|
|
78
|
-
|
|
79
|
-
) -> Dict[Any, Any]:
|
|
80
|
-
model: Union[Dict[Any, Any], List[Any]]
|
|
61
|
+
def get_model_by_path(schema: dict[str, Any] | list[Any], keys: list[str] | list[int]) -> dict[Any, Any]:
|
|
62
|
+
model: dict[Any, Any] | list[Any]
|
|
81
63
|
if not keys:
|
|
82
64
|
model = schema
|
|
83
65
|
elif len(keys) == 1:
|
|
84
|
-
if isinstance(schema, dict)
|
|
85
|
-
model = schema.get(keys[0], {}) # type: ignore
|
|
86
|
-
else: # pragma: no cover
|
|
87
|
-
model = schema[int(keys[0])]
|
|
66
|
+
model = schema.get(str(keys[0]), {}) if isinstance(schema, dict) else schema[int(keys[0])]
|
|
88
67
|
elif isinstance(schema, dict):
|
|
89
|
-
model = get_model_by_path(schema[keys[0]], keys[1:])
|
|
68
|
+
model = get_model_by_path(schema[str(keys[0])], keys[1:])
|
|
90
69
|
else:
|
|
91
70
|
model = get_model_by_path(schema[int(keys[0])], keys[1:])
|
|
92
71
|
if isinstance(model, dict):
|
|
93
72
|
return model
|
|
73
|
+
msg = f"Does not support json pointer to array. schema={schema}, key={keys}"
|
|
94
74
|
raise NotImplementedError( # pragma: no cover
|
|
95
|
-
|
|
75
|
+
msg
|
|
96
76
|
)
|
|
97
77
|
|
|
98
78
|
|
|
99
|
-
json_schema_data_formats:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
79
|
+
json_schema_data_formats: dict[str, dict[str, Types]] = {
|
|
80
|
+
"integer": {
|
|
81
|
+
"int32": Types.int32,
|
|
82
|
+
"int64": Types.int64,
|
|
83
|
+
"default": Types.integer,
|
|
84
|
+
"date-time": Types.date_time,
|
|
85
|
+
"unix-time": Types.int64,
|
|
106
86
|
},
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
87
|
+
"number": {
|
|
88
|
+
"float": Types.float,
|
|
89
|
+
"double": Types.double,
|
|
90
|
+
"decimal": Types.decimal,
|
|
91
|
+
"date-time": Types.date_time,
|
|
92
|
+
"time": Types.time,
|
|
93
|
+
"default": Types.number,
|
|
114
94
|
},
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
95
|
+
"string": {
|
|
96
|
+
"default": Types.string,
|
|
97
|
+
"byte": Types.byte, # base64 encoded string
|
|
98
|
+
"binary": Types.binary,
|
|
99
|
+
"date": Types.date,
|
|
100
|
+
"date-time": Types.date_time,
|
|
101
|
+
"duration": Types.timedelta,
|
|
102
|
+
"time": Types.time,
|
|
103
|
+
"password": Types.password,
|
|
104
|
+
"path": Types.path,
|
|
105
|
+
"email": Types.email,
|
|
106
|
+
"idn-email": Types.email,
|
|
107
|
+
"uuid": Types.uuid,
|
|
108
|
+
"uuid1": Types.uuid1,
|
|
109
|
+
"uuid2": Types.uuid2,
|
|
110
|
+
"uuid3": Types.uuid3,
|
|
111
|
+
"uuid4": Types.uuid4,
|
|
112
|
+
"uuid5": Types.uuid5,
|
|
113
|
+
"uri": Types.uri,
|
|
114
|
+
"uri-reference": Types.string,
|
|
115
|
+
"hostname": Types.hostname,
|
|
116
|
+
"ipv4": Types.ipv4,
|
|
117
|
+
"ipv4-network": Types.ipv4_network,
|
|
118
|
+
"ipv6": Types.ipv6,
|
|
119
|
+
"ipv6-network": Types.ipv6_network,
|
|
120
|
+
"decimal": Types.decimal,
|
|
121
|
+
"integer": Types.integer,
|
|
142
122
|
},
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
123
|
+
"boolean": {"default": Types.boolean},
|
|
124
|
+
"object": {"default": Types.object},
|
|
125
|
+
"null": {"default": Types.null},
|
|
126
|
+
"array": {"default": Types.array},
|
|
147
127
|
}
|
|
148
128
|
|
|
149
129
|
|
|
150
130
|
class JSONReference(_enum.Enum):
|
|
151
|
-
LOCAL =
|
|
152
|
-
REMOTE =
|
|
153
|
-
URL =
|
|
131
|
+
LOCAL = "LOCAL"
|
|
132
|
+
REMOTE = "REMOTE"
|
|
133
|
+
URL = "URL"
|
|
154
134
|
|
|
155
135
|
|
|
156
136
|
class Discriminator(BaseModel):
|
|
157
|
-
propertyName: str
|
|
158
|
-
mapping: Optional[
|
|
137
|
+
propertyName: str # noqa: N815
|
|
138
|
+
mapping: Optional[dict[str, str]] = None # noqa: UP045
|
|
159
139
|
|
|
160
140
|
|
|
161
141
|
class JsonSchemaObject(BaseModel):
|
|
@@ -163,102 +143,102 @@ class JsonSchemaObject(BaseModel):
|
|
|
163
143
|
if PYDANTIC_V2:
|
|
164
144
|
|
|
165
145
|
@classmethod
|
|
166
|
-
def get_fields(cls) ->
|
|
146
|
+
def get_fields(cls) -> dict[str, Any]:
|
|
167
147
|
return cls.model_fields
|
|
168
148
|
|
|
169
149
|
else:
|
|
170
150
|
|
|
171
151
|
@classmethod
|
|
172
|
-
def get_fields(cls) ->
|
|
152
|
+
def get_fields(cls) -> dict[str, Any]:
|
|
173
153
|
return cls.__fields__
|
|
174
154
|
|
|
175
155
|
@classmethod
|
|
176
156
|
def model_rebuild(cls) -> None:
|
|
177
157
|
cls.update_forward_refs()
|
|
178
158
|
|
|
179
|
-
__constraint_fields__:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
159
|
+
__constraint_fields__: set[str] = { # noqa: RUF012
|
|
160
|
+
"exclusiveMinimum",
|
|
161
|
+
"minimum",
|
|
162
|
+
"exclusiveMaximum",
|
|
163
|
+
"maximum",
|
|
164
|
+
"multipleOf",
|
|
165
|
+
"minItems",
|
|
166
|
+
"maxItems",
|
|
167
|
+
"minLength",
|
|
168
|
+
"maxLength",
|
|
169
|
+
"pattern",
|
|
170
|
+
"uniqueItems",
|
|
191
171
|
}
|
|
192
|
-
__extra_key__: str = SPECIAL_PATH_FORMAT.format(
|
|
172
|
+
__extra_key__: str = SPECIAL_PATH_FORMAT.format("extras")
|
|
193
173
|
|
|
194
|
-
@model_validator(mode=
|
|
195
|
-
def validate_exclusive_maximum_and_exclusive_minimum(cls, values: Any) -> Any:
|
|
174
|
+
@model_validator(mode="before")
|
|
175
|
+
def validate_exclusive_maximum_and_exclusive_minimum(cls, values: Any) -> Any: # noqa: N805
|
|
196
176
|
if not isinstance(values, dict):
|
|
197
177
|
return values
|
|
198
|
-
exclusive_maximum:
|
|
199
|
-
exclusive_minimum:
|
|
178
|
+
exclusive_maximum: float | bool | None = values.get("exclusiveMaximum")
|
|
179
|
+
exclusive_minimum: float | bool | None = values.get("exclusiveMinimum")
|
|
200
180
|
|
|
201
181
|
if exclusive_maximum is True:
|
|
202
|
-
values[
|
|
203
|
-
del values[
|
|
182
|
+
values["exclusiveMaximum"] = values["maximum"]
|
|
183
|
+
del values["maximum"]
|
|
204
184
|
elif exclusive_maximum is False:
|
|
205
|
-
del values[
|
|
185
|
+
del values["exclusiveMaximum"]
|
|
206
186
|
if exclusive_minimum is True:
|
|
207
|
-
values[
|
|
208
|
-
del values[
|
|
187
|
+
values["exclusiveMinimum"] = values["minimum"]
|
|
188
|
+
del values["minimum"]
|
|
209
189
|
elif exclusive_minimum is False:
|
|
210
|
-
del values[
|
|
190
|
+
del values["exclusiveMinimum"]
|
|
211
191
|
return values
|
|
212
192
|
|
|
213
|
-
@field_validator(
|
|
214
|
-
def validate_ref(cls, value: Any) -> Any:
|
|
215
|
-
if isinstance(value, str) and
|
|
216
|
-
if value.endswith(
|
|
193
|
+
@field_validator("ref")
|
|
194
|
+
def validate_ref(cls, value: Any) -> Any: # noqa: N805
|
|
195
|
+
if isinstance(value, str) and "#" in value:
|
|
196
|
+
if value.endswith("#/"):
|
|
217
197
|
return value[:-1]
|
|
218
|
-
|
|
198
|
+
if "#/" in value or value[0] == "#" or value[-1] == "#":
|
|
219
199
|
return value
|
|
220
|
-
return value.replace(
|
|
200
|
+
return value.replace("#", "#/")
|
|
221
201
|
return value
|
|
222
202
|
|
|
223
|
-
items: Union[
|
|
224
|
-
uniqueItems: Optional[bool] = None
|
|
225
|
-
type: Union[str,
|
|
226
|
-
format: Optional[str] = None
|
|
227
|
-
pattern: Optional[str] = None
|
|
228
|
-
minLength: Optional[int] = None
|
|
229
|
-
maxLength: Optional[int] = None
|
|
230
|
-
minimum: Optional[UnionIntFloat] = None
|
|
231
|
-
maximum: Optional[UnionIntFloat] = None
|
|
232
|
-
minItems: Optional[int] = None
|
|
233
|
-
maxItems: Optional[int] = None
|
|
234
|
-
multipleOf: Optional[float] = None
|
|
235
|
-
exclusiveMaximum: Union[float, bool
|
|
236
|
-
exclusiveMinimum: Union[float, bool
|
|
237
|
-
additionalProperties: Union[JsonSchemaObject, bool
|
|
238
|
-
patternProperties: Optional[
|
|
239
|
-
oneOf:
|
|
240
|
-
anyOf:
|
|
241
|
-
allOf:
|
|
242
|
-
enum:
|
|
243
|
-
writeOnly: Optional[bool] = None
|
|
244
|
-
readOnly: Optional[bool] = None
|
|
245
|
-
properties: Optional[
|
|
246
|
-
required:
|
|
247
|
-
ref: Optional[str] = Field(default=None, alias=
|
|
248
|
-
nullable: Optional[bool] = False
|
|
249
|
-
x_enum_varnames:
|
|
250
|
-
description: Optional[str] = None
|
|
251
|
-
title: Optional[str] = None
|
|
203
|
+
items: Optional[Union[list[JsonSchemaObject], JsonSchemaObject, bool]] = None # noqa: UP007, UP045
|
|
204
|
+
uniqueItems: Optional[bool] = None # noqa: N815, UP045
|
|
205
|
+
type: Optional[Union[str, list[str]]] = None # noqa: UP007, UP045
|
|
206
|
+
format: Optional[str] = None # noqa: UP045
|
|
207
|
+
pattern: Optional[str] = None # noqa: UP045
|
|
208
|
+
minLength: Optional[int] = None # noqa: N815,UP045
|
|
209
|
+
maxLength: Optional[int] = None # noqa: N815,UP045
|
|
210
|
+
minimum: Optional[UnionIntFloat] = None # noqa: UP045
|
|
211
|
+
maximum: Optional[UnionIntFloat] = None # noqa: UP045
|
|
212
|
+
minItems: Optional[int] = None # noqa: N815,UP045
|
|
213
|
+
maxItems: Optional[int] = None # noqa: N815,UP045
|
|
214
|
+
multipleOf: Optional[float] = None # noqa: N815, UP045
|
|
215
|
+
exclusiveMaximum: Optional[Union[float, bool]] = None # noqa: N815, UP007, UP045
|
|
216
|
+
exclusiveMinimum: Optional[Union[float, bool]] = None # noqa: N815, UP007, UP045
|
|
217
|
+
additionalProperties: Optional[Union[JsonSchemaObject, bool]] = None # noqa: N815, UP007, UP045
|
|
218
|
+
patternProperties: Optional[dict[str, JsonSchemaObject]] = None # noqa: N815, UP045
|
|
219
|
+
oneOf: list[JsonSchemaObject] = [] # noqa: N815, RUF012
|
|
220
|
+
anyOf: list[JsonSchemaObject] = [] # noqa: N815, RUF012
|
|
221
|
+
allOf: list[JsonSchemaObject] = [] # noqa: N815, RUF012
|
|
222
|
+
enum: list[Any] = [] # noqa: RUF012
|
|
223
|
+
writeOnly: Optional[bool] = None # noqa: N815, UP045
|
|
224
|
+
readOnly: Optional[bool] = None # noqa: N815, UP045
|
|
225
|
+
properties: Optional[dict[str, Union[JsonSchemaObject, bool]]] = None # noqa: UP007, UP045
|
|
226
|
+
required: list[str] = [] # noqa: RUF012
|
|
227
|
+
ref: Optional[str] = Field(default=None, alias="$ref") # noqa: UP045
|
|
228
|
+
nullable: Optional[bool] = False # noqa: UP045
|
|
229
|
+
x_enum_varnames: list[str] = Field(default=[], alias="x-enum-varnames")
|
|
230
|
+
description: Optional[str] = None # noqa: UP045
|
|
231
|
+
title: Optional[str] = None # noqa: UP045
|
|
252
232
|
example: Any = None
|
|
253
233
|
examples: Any = None
|
|
254
234
|
default: Any = None
|
|
255
|
-
id: Optional[str] = Field(default=None, alias=
|
|
256
|
-
custom_type_path: Optional[str] = Field(default=None, alias=
|
|
257
|
-
custom_base_path: Optional[str] = Field(default=None, alias=
|
|
258
|
-
extras:
|
|
259
|
-
discriminator: Union[Discriminator, str
|
|
235
|
+
id: Optional[str] = Field(default=None, alias="$id") # noqa: UP045
|
|
236
|
+
custom_type_path: Optional[str] = Field(default=None, alias="customTypePath") # noqa: UP045
|
|
237
|
+
custom_base_path: Optional[str] = Field(default=None, alias="customBasePath") # noqa: UP045
|
|
238
|
+
extras: dict[str, Any] = Field(alias=__extra_key__, default_factory=dict)
|
|
239
|
+
discriminator: Optional[Union[Discriminator, str]] = None # noqa: UP007, UP045
|
|
260
240
|
if PYDANTIC_V2:
|
|
261
|
-
model_config = ConfigDict( # pyright: ignore
|
|
241
|
+
model_config = ConfigDict( # pyright: ignore[reportPossiblyUnboundVariable]
|
|
262
242
|
arbitrary_types_allowed=True,
|
|
263
243
|
ignored_types=(cached_property,),
|
|
264
244
|
)
|
|
@@ -274,178 +254,171 @@ class JsonSchemaObject(BaseModel):
|
|
|
274
254
|
def __init__(self, **data: Any) -> None:
|
|
275
255
|
super().__init__(**data)
|
|
276
256
|
self.extras = {k: v for k, v in data.items() if k not in EXCLUDE_FIELD_KEYS}
|
|
277
|
-
if
|
|
278
|
-
self.extras[
|
|
257
|
+
if "const" in data.get(self.__extra_key__, {}):
|
|
258
|
+
self.extras["const"] = data[self.__extra_key__]["const"]
|
|
279
259
|
|
|
280
260
|
@cached_property
|
|
281
261
|
def is_object(self) -> bool:
|
|
282
|
-
return (
|
|
283
|
-
self.
|
|
284
|
-
or self.type == 'object'
|
|
285
|
-
and not self.allOf
|
|
286
|
-
and not self.oneOf
|
|
287
|
-
and not self.anyOf
|
|
288
|
-
and not self.ref
|
|
262
|
+
return self.properties is not None or (
|
|
263
|
+
self.type == "object" and not self.allOf and not self.oneOf and not self.anyOf and not self.ref
|
|
289
264
|
)
|
|
290
265
|
|
|
291
266
|
@cached_property
|
|
292
267
|
def is_array(self) -> bool:
|
|
293
|
-
return self.items is not None or self.type ==
|
|
268
|
+
return self.items is not None or self.type == "array"
|
|
294
269
|
|
|
295
270
|
@cached_property
|
|
296
271
|
def ref_object_name(self) -> str: # pragma: no cover
|
|
297
|
-
return self.ref.rsplit(
|
|
272
|
+
return (self.ref or "").rsplit("/", 1)[-1]
|
|
298
273
|
|
|
299
|
-
@field_validator(
|
|
300
|
-
def validate_items(cls, values: Any) -> Any:
|
|
274
|
+
@field_validator("items", mode="before")
|
|
275
|
+
def validate_items(cls, values: Any) -> Any: # noqa: N805
|
|
301
276
|
# this condition expects empty dict
|
|
302
277
|
return values or None
|
|
303
278
|
|
|
304
279
|
@cached_property
|
|
305
280
|
def has_default(self) -> bool:
|
|
306
|
-
return
|
|
281
|
+
return "default" in self.__fields_set__ or "default_factory" in self.extras
|
|
307
282
|
|
|
308
283
|
@cached_property
|
|
309
284
|
def has_constraint(self) -> bool:
|
|
310
285
|
return bool(self.__constraint_fields__ & self.__fields_set__)
|
|
311
286
|
|
|
312
287
|
@cached_property
|
|
313
|
-
def ref_type(self) ->
|
|
288
|
+
def ref_type(self) -> JSONReference | None:
|
|
314
289
|
if self.ref:
|
|
315
290
|
return get_ref_type(self.ref)
|
|
316
291
|
return None # pragma: no cover
|
|
317
292
|
|
|
318
293
|
@cached_property
|
|
319
294
|
def type_has_null(self) -> bool:
|
|
320
|
-
return isinstance(self.type, list) and
|
|
295
|
+
return isinstance(self.type, list) and "null" in self.type
|
|
321
296
|
|
|
322
297
|
|
|
323
298
|
@lru_cache
|
|
324
299
|
def get_ref_type(ref: str) -> JSONReference:
|
|
325
|
-
if ref[0] ==
|
|
300
|
+
if ref[0] == "#":
|
|
326
301
|
return JSONReference.LOCAL
|
|
327
|
-
|
|
302
|
+
if is_url(ref):
|
|
328
303
|
return JSONReference.URL
|
|
329
304
|
return JSONReference.REMOTE
|
|
330
305
|
|
|
331
306
|
|
|
332
|
-
def _get_type(type_: str, format__:
|
|
307
|
+
def _get_type(type_: str, format__: str | None = None) -> Types:
|
|
333
308
|
if type_ not in json_schema_data_formats:
|
|
334
309
|
return Types.any
|
|
335
|
-
data_formats:
|
|
336
|
-
'default' if format__ is None else format__
|
|
337
|
-
)
|
|
310
|
+
data_formats: Types | None = json_schema_data_formats[type_].get("default" if format__ is None else format__)
|
|
338
311
|
if data_formats is not None:
|
|
339
312
|
return data_formats
|
|
340
313
|
|
|
341
|
-
warn(f
|
|
342
|
-
return json_schema_data_formats[type_][
|
|
314
|
+
warn(f"format of {format__!r} not understood for {type_!r} - using default", stacklevel=2)
|
|
315
|
+
return json_schema_data_formats[type_]["default"]
|
|
343
316
|
|
|
344
317
|
|
|
345
318
|
JsonSchemaObject.model_rebuild()
|
|
346
319
|
|
|
347
|
-
DEFAULT_FIELD_KEYS:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
320
|
+
DEFAULT_FIELD_KEYS: set[str] = {
|
|
321
|
+
"example",
|
|
322
|
+
"examples",
|
|
323
|
+
"description",
|
|
324
|
+
"discriminator",
|
|
325
|
+
"title",
|
|
326
|
+
"const",
|
|
327
|
+
"default_factory",
|
|
355
328
|
}
|
|
356
329
|
|
|
357
|
-
EXCLUDE_FIELD_KEYS_IN_JSON_SCHEMA:
|
|
358
|
-
|
|
359
|
-
|
|
330
|
+
EXCLUDE_FIELD_KEYS_IN_JSON_SCHEMA: set[str] = {
|
|
331
|
+
"readOnly",
|
|
332
|
+
"writeOnly",
|
|
360
333
|
}
|
|
361
334
|
|
|
362
335
|
EXCLUDE_FIELD_KEYS = (
|
|
363
|
-
set(JsonSchemaObject.get_fields()) # pyright: ignore
|
|
336
|
+
set(JsonSchemaObject.get_fields()) # pyright: ignore[reportAttributeAccessIssue]
|
|
364
337
|
- DEFAULT_FIELD_KEYS
|
|
365
338
|
- EXCLUDE_FIELD_KEYS_IN_JSON_SCHEMA
|
|
366
339
|
) | {
|
|
367
|
-
|
|
368
|
-
|
|
340
|
+
"$id",
|
|
341
|
+
"$ref",
|
|
369
342
|
JsonSchemaObject.__extra_key__,
|
|
370
343
|
}
|
|
371
344
|
|
|
372
345
|
|
|
373
|
-
@snooper_to_methods(
|
|
346
|
+
@snooper_to_methods() # noqa: PLR0904
|
|
374
347
|
class JsonSchemaParser(Parser):
|
|
375
|
-
SCHEMA_PATHS: ClassVar[
|
|
376
|
-
SCHEMA_OBJECT_TYPE: ClassVar[
|
|
348
|
+
SCHEMA_PATHS: ClassVar[list[str]] = ["#/definitions", "#/$defs"]
|
|
349
|
+
SCHEMA_OBJECT_TYPE: ClassVar[type[JsonSchemaObject]] = JsonSchemaObject
|
|
377
350
|
|
|
378
|
-
def __init__(
|
|
351
|
+
def __init__( # noqa: PLR0913
|
|
379
352
|
self,
|
|
380
|
-
source:
|
|
353
|
+
source: str | Path | list[Path] | ParseResult,
|
|
381
354
|
*,
|
|
382
|
-
data_model_type:
|
|
383
|
-
data_model_root_type:
|
|
384
|
-
data_type_manager_type:
|
|
385
|
-
data_model_field_type:
|
|
386
|
-
base_class:
|
|
387
|
-
additional_imports:
|
|
388
|
-
custom_template_dir:
|
|
389
|
-
extra_template_data:
|
|
390
|
-
target_python_version: PythonVersion =
|
|
391
|
-
dump_resolve_reference_action:
|
|
355
|
+
data_model_type: type[DataModel] = pydantic_model.BaseModel,
|
|
356
|
+
data_model_root_type: type[DataModel] = pydantic_model.CustomRootType,
|
|
357
|
+
data_type_manager_type: type[DataTypeManager] = pydantic_model.DataTypeManager,
|
|
358
|
+
data_model_field_type: type[DataModelFieldBase] = pydantic_model.DataModelField,
|
|
359
|
+
base_class: str | None = None,
|
|
360
|
+
additional_imports: list[str] | None = None,
|
|
361
|
+
custom_template_dir: Path | None = None,
|
|
362
|
+
extra_template_data: defaultdict[str, dict[str, Any]] | None = None,
|
|
363
|
+
target_python_version: PythonVersion = PythonVersionMin,
|
|
364
|
+
dump_resolve_reference_action: Callable[[Iterable[str]], str] | None = None,
|
|
392
365
|
validation: bool = False,
|
|
393
366
|
field_constraints: bool = False,
|
|
394
367
|
snake_case_field: bool = False,
|
|
395
368
|
strip_default_none: bool = False,
|
|
396
|
-
aliases:
|
|
369
|
+
aliases: Mapping[str, str] | None = None,
|
|
397
370
|
allow_population_by_field_name: bool = False,
|
|
398
371
|
apply_default_values_for_required_fields: bool = False,
|
|
399
372
|
allow_extra_fields: bool = False,
|
|
400
373
|
force_optional_for_required_fields: bool = False,
|
|
401
|
-
class_name:
|
|
374
|
+
class_name: str | None = None,
|
|
402
375
|
use_standard_collections: bool = False,
|
|
403
|
-
base_path:
|
|
376
|
+
base_path: Path | None = None,
|
|
404
377
|
use_schema_description: bool = False,
|
|
405
378
|
use_field_description: bool = False,
|
|
406
379
|
use_default_kwarg: bool = False,
|
|
407
380
|
reuse_model: bool = False,
|
|
408
|
-
encoding: str =
|
|
409
|
-
enum_field_as_literal:
|
|
381
|
+
encoding: str = "utf-8",
|
|
382
|
+
enum_field_as_literal: LiteralType | None = None,
|
|
410
383
|
use_one_literal_as_default: bool = False,
|
|
411
384
|
set_default_enum_member: bool = False,
|
|
412
385
|
use_subclass_enum: bool = False,
|
|
413
386
|
strict_nullable: bool = False,
|
|
414
387
|
use_generic_container_types: bool = False,
|
|
415
388
|
enable_faux_immutability: bool = False,
|
|
416
|
-
remote_text_cache:
|
|
389
|
+
remote_text_cache: DefaultPutDict[str, str] | None = None,
|
|
417
390
|
disable_appending_item_suffix: bool = False,
|
|
418
|
-
strict_types:
|
|
419
|
-
empty_enum_field_name:
|
|
420
|
-
custom_class_name_generator:
|
|
421
|
-
field_extra_keys:
|
|
391
|
+
strict_types: Sequence[StrictTypes] | None = None,
|
|
392
|
+
empty_enum_field_name: str | None = None,
|
|
393
|
+
custom_class_name_generator: Callable[[str], str] | None = None,
|
|
394
|
+
field_extra_keys: set[str] | None = None,
|
|
422
395
|
field_include_all_keys: bool = False,
|
|
423
|
-
field_extra_keys_without_x_prefix:
|
|
424
|
-
wrap_string_literal:
|
|
396
|
+
field_extra_keys_without_x_prefix: set[str] | None = None,
|
|
397
|
+
wrap_string_literal: bool | None = None,
|
|
425
398
|
use_title_as_name: bool = False,
|
|
426
399
|
use_operation_id_as_name: bool = False,
|
|
427
400
|
use_unique_items_as_set: bool = False,
|
|
428
|
-
http_headers:
|
|
401
|
+
http_headers: Sequence[tuple[str, str]] | None = None,
|
|
429
402
|
http_ignore_tls: bool = False,
|
|
430
403
|
use_annotated: bool = False,
|
|
431
404
|
use_non_positive_negative_number_constrained_types: bool = False,
|
|
432
|
-
original_field_name_delimiter:
|
|
405
|
+
original_field_name_delimiter: str | None = None,
|
|
433
406
|
use_double_quotes: bool = False,
|
|
434
407
|
use_union_operator: bool = False,
|
|
435
408
|
allow_responses_without_content: bool = False,
|
|
436
409
|
collapse_root_models: bool = False,
|
|
437
|
-
special_field_name_prefix:
|
|
410
|
+
special_field_name_prefix: str | None = None,
|
|
438
411
|
remove_special_field_name_prefix: bool = False,
|
|
439
412
|
capitalise_enum_members: bool = False,
|
|
440
413
|
keep_model_order: bool = False,
|
|
441
|
-
known_third_party:
|
|
442
|
-
custom_formatters:
|
|
443
|
-
custom_formatters_kwargs:
|
|
414
|
+
known_third_party: list[str] | None = None,
|
|
415
|
+
custom_formatters: list[str] | None = None,
|
|
416
|
+
custom_formatters_kwargs: dict[str, Any] | None = None,
|
|
444
417
|
use_pendulum: bool = False,
|
|
445
|
-
http_query_parameters:
|
|
418
|
+
http_query_parameters: Sequence[tuple[str, str]] | None = None,
|
|
446
419
|
treat_dots_as_module: bool = False,
|
|
447
420
|
use_exact_imports: bool = False,
|
|
448
|
-
default_field_extras:
|
|
421
|
+
default_field_extras: dict[str, Any] | None = None,
|
|
449
422
|
target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
|
|
450
423
|
keyword_only: bool = False,
|
|
451
424
|
no_alias: bool = False,
|
|
@@ -524,12 +497,12 @@ class JsonSchemaParser(Parser):
|
|
|
524
497
|
no_alias=no_alias,
|
|
525
498
|
)
|
|
526
499
|
|
|
527
|
-
self.remote_object_cache: DefaultPutDict[str,
|
|
528
|
-
self.raw_obj:
|
|
529
|
-
self._root_id: Optional[str] = None
|
|
530
|
-
self._root_id_base_path: Optional[str] = None
|
|
531
|
-
self.reserved_refs:
|
|
532
|
-
self.field_keys:
|
|
500
|
+
self.remote_object_cache: DefaultPutDict[str, dict[str, Any]] = DefaultPutDict()
|
|
501
|
+
self.raw_obj: dict[Any, Any] = {}
|
|
502
|
+
self._root_id: Optional[str] = None # noqa: UP045
|
|
503
|
+
self._root_id_base_path: Optional[str] = None # noqa: UP045
|
|
504
|
+
self.reserved_refs: defaultdict[tuple[str, ...], set[str]] = defaultdict(set)
|
|
505
|
+
self.field_keys: set[str] = {
|
|
533
506
|
*DEFAULT_FIELD_KEYS,
|
|
534
507
|
*self.field_extra_keys,
|
|
535
508
|
*self.field_extra_keys_without_x_prefix,
|
|
@@ -543,19 +516,15 @@ class JsonSchemaParser(Parser):
|
|
|
543
516
|
else:
|
|
544
517
|
self.get_field_extra_key = lambda key: key
|
|
545
518
|
|
|
546
|
-
def get_field_extras(self, obj: JsonSchemaObject) ->
|
|
519
|
+
def get_field_extras(self, obj: JsonSchemaObject) -> dict[str, Any]:
|
|
547
520
|
if self.field_include_all_keys:
|
|
548
521
|
extras = {
|
|
549
|
-
self.get_field_extra_key(
|
|
550
|
-
k.lstrip('x-') if k in self.field_extra_keys_without_x_prefix else k
|
|
551
|
-
): v
|
|
522
|
+
self.get_field_extra_key(k.lstrip("x-") if k in self.field_extra_keys_without_x_prefix else k): v
|
|
552
523
|
for k, v in obj.extras.items()
|
|
553
524
|
}
|
|
554
525
|
else:
|
|
555
526
|
extras = {
|
|
556
|
-
self.get_field_extra_key(
|
|
557
|
-
k.lstrip('x-') if k in self.field_extra_keys_without_x_prefix else k
|
|
558
|
-
): v
|
|
527
|
+
self.get_field_extra_key(k.lstrip("x-") if k in self.field_extra_keys_without_x_prefix else k): v
|
|
559
528
|
for k, v in obj.extras.items()
|
|
560
529
|
if k in self.field_keys
|
|
561
530
|
}
|
|
@@ -564,15 +533,15 @@ class JsonSchemaParser(Parser):
|
|
|
564
533
|
return extras
|
|
565
534
|
|
|
566
535
|
@cached_property
|
|
567
|
-
def schema_paths(self) ->
|
|
568
|
-
return [(s, s.lstrip(
|
|
536
|
+
def schema_paths(self) -> list[tuple[str, list[str]]]:
|
|
537
|
+
return [(s, s.lstrip("#/").split("/")) for s in self.SCHEMA_PATHS]
|
|
569
538
|
|
|
570
539
|
@property
|
|
571
|
-
def root_id(self) ->
|
|
540
|
+
def root_id(self) -> str | None:
|
|
572
541
|
return self.model_resolver.root_id
|
|
573
542
|
|
|
574
543
|
@root_id.setter
|
|
575
|
-
def root_id(self, value:
|
|
544
|
+
def root_id(self, value: str | None) -> None:
|
|
576
545
|
self.model_resolver.set_root_id(value)
|
|
577
546
|
|
|
578
547
|
def should_parse_enum_as_literal(self, obj: JsonSchemaObject) -> bool:
|
|
@@ -582,26 +551,18 @@ class JsonSchemaParser(Parser):
|
|
|
582
551
|
|
|
583
552
|
def is_constraints_field(self, obj: JsonSchemaObject) -> bool:
|
|
584
553
|
return obj.is_array or (
|
|
585
|
-
self.field_constraints
|
|
586
|
-
and not (
|
|
587
|
-
obj.ref
|
|
588
|
-
or obj.anyOf
|
|
589
|
-
or obj.oneOf
|
|
590
|
-
or obj.allOf
|
|
591
|
-
or obj.is_object
|
|
592
|
-
or obj.enum
|
|
593
|
-
)
|
|
554
|
+
self.field_constraints and not (obj.ref or obj.anyOf or obj.oneOf or obj.allOf or obj.is_object or obj.enum)
|
|
594
555
|
)
|
|
595
556
|
|
|
596
|
-
def get_object_field(
|
|
557
|
+
def get_object_field( # noqa: PLR0913
|
|
597
558
|
self,
|
|
598
559
|
*,
|
|
599
|
-
field_name:
|
|
560
|
+
field_name: str | None,
|
|
600
561
|
field: JsonSchemaObject,
|
|
601
562
|
required: bool,
|
|
602
563
|
field_type: DataType,
|
|
603
|
-
alias:
|
|
604
|
-
original_field_name:
|
|
564
|
+
alias: str | None,
|
|
565
|
+
original_field_name: str | None,
|
|
605
566
|
) -> DataModelFieldBase:
|
|
606
567
|
return self.data_model_field_type(
|
|
607
568
|
name=field_name,
|
|
@@ -610,9 +571,7 @@ class JsonSchemaParser(Parser):
|
|
|
610
571
|
required=required,
|
|
611
572
|
alias=alias,
|
|
612
573
|
constraints=field.dict() if self.is_constraints_field(field) else None,
|
|
613
|
-
nullable=field.nullable
|
|
614
|
-
if self.strict_nullable and (field.has_default or required)
|
|
615
|
-
else None,
|
|
574
|
+
nullable=field.nullable if self.strict_nullable and (field.has_default or required) else None,
|
|
616
575
|
strip_default_none=self.strip_default_none,
|
|
617
576
|
extras=self.get_field_extras(field),
|
|
618
577
|
use_annotated=self.use_annotated,
|
|
@@ -625,10 +584,8 @@ class JsonSchemaParser(Parser):
|
|
|
625
584
|
|
|
626
585
|
def get_data_type(self, obj: JsonSchemaObject) -> DataType:
|
|
627
586
|
if obj.type is None:
|
|
628
|
-
if
|
|
629
|
-
return self.data_type_manager.get_data_type_from_value(
|
|
630
|
-
obj.extras['const']
|
|
631
|
-
)
|
|
587
|
+
if "const" in obj.extras:
|
|
588
|
+
return self.data_type_manager.get_data_type_from_value(obj.extras["const"])
|
|
632
589
|
return self.data_type_manager.get_data_type(
|
|
633
590
|
Types.any,
|
|
634
591
|
)
|
|
@@ -641,14 +598,10 @@ class JsonSchemaParser(Parser):
|
|
|
641
598
|
|
|
642
599
|
if isinstance(obj.type, list):
|
|
643
600
|
return self.data_type(
|
|
644
|
-
data_types=[
|
|
645
|
-
|
|
646
|
-
for t in obj.type
|
|
647
|
-
if t != 'null'
|
|
648
|
-
],
|
|
649
|
-
is_optional='null' in obj.type,
|
|
601
|
+
data_types=[_get_data_type(t, obj.format or "default") for t in obj.type if t != "null"],
|
|
602
|
+
is_optional="null" in obj.type,
|
|
650
603
|
)
|
|
651
|
-
return _get_data_type(obj.type, obj.format or
|
|
604
|
+
return _get_data_type(obj.type, obj.format or "default")
|
|
652
605
|
|
|
653
606
|
def get_ref_data_type(self, ref: str) -> DataType:
|
|
654
607
|
reference = self.model_resolver.add_ref(ref)
|
|
@@ -656,25 +609,21 @@ class JsonSchemaParser(Parser):
|
|
|
656
609
|
|
|
657
610
|
def set_additional_properties(self, name: str, obj: JsonSchemaObject) -> None:
|
|
658
611
|
if isinstance(obj.additionalProperties, bool):
|
|
659
|
-
self.extra_template_data[name][
|
|
660
|
-
obj.additionalProperties
|
|
661
|
-
)
|
|
612
|
+
self.extra_template_data[name]["additionalProperties"] = obj.additionalProperties
|
|
662
613
|
|
|
663
614
|
def set_title(self, name: str, obj: JsonSchemaObject) -> None:
|
|
664
615
|
if obj.title:
|
|
665
|
-
self.extra_template_data[name][
|
|
616
|
+
self.extra_template_data[name]["title"] = obj.title
|
|
666
617
|
|
|
667
|
-
def _deep_merge(
|
|
668
|
-
self, dict1: Dict[Any, Any], dict2: Dict[Any, Any]
|
|
669
|
-
) -> Dict[Any, Any]:
|
|
618
|
+
def _deep_merge(self, dict1: dict[Any, Any], dict2: dict[Any, Any]) -> dict[Any, Any]:
|
|
670
619
|
result = dict1.copy()
|
|
671
620
|
for key, value in dict2.items():
|
|
672
621
|
if key in result:
|
|
673
622
|
if isinstance(result[key], dict) and isinstance(value, dict):
|
|
674
623
|
result[key] = self._deep_merge(result[key], value)
|
|
675
624
|
continue
|
|
676
|
-
|
|
677
|
-
result[key]
|
|
625
|
+
if isinstance(result[key], list) and isinstance(value, list):
|
|
626
|
+
result[key] += value
|
|
678
627
|
continue
|
|
679
628
|
result[key] = value
|
|
680
629
|
return result
|
|
@@ -683,34 +632,17 @@ class JsonSchemaParser(Parser):
|
|
|
683
632
|
self,
|
|
684
633
|
name: str,
|
|
685
634
|
obj: JsonSchemaObject,
|
|
686
|
-
path:
|
|
635
|
+
path: list[str],
|
|
687
636
|
target_attribute_name: str,
|
|
688
|
-
) ->
|
|
689
|
-
base_object = obj.dict(
|
|
690
|
-
|
|
691
|
-
)
|
|
692
|
-
combined_schemas: List[JsonSchemaObject] = []
|
|
637
|
+
) -> list[DataType]:
|
|
638
|
+
base_object = obj.dict(exclude={target_attribute_name}, exclude_unset=True, by_alias=True)
|
|
639
|
+
combined_schemas: list[JsonSchemaObject] = []
|
|
693
640
|
refs = []
|
|
694
|
-
for index, target_attribute in enumerate(
|
|
695
|
-
getattr(obj, target_attribute_name, [])
|
|
696
|
-
):
|
|
641
|
+
for index, target_attribute in enumerate(getattr(obj, target_attribute_name, [])):
|
|
697
642
|
if target_attribute.ref:
|
|
698
643
|
combined_schemas.append(target_attribute)
|
|
699
644
|
refs.append(index)
|
|
700
645
|
# TODO: support partial ref
|
|
701
|
-
# {
|
|
702
|
-
# "type": "integer",
|
|
703
|
-
# "oneOf": [
|
|
704
|
-
# { "minimum": 5 },
|
|
705
|
-
# { "$ref": "#/definitions/positive" }
|
|
706
|
-
# ],
|
|
707
|
-
# "definitions": {
|
|
708
|
-
# "positive": {
|
|
709
|
-
# "minimum": 0,
|
|
710
|
-
# "exclusiveMinimum": true
|
|
711
|
-
# }
|
|
712
|
-
# }
|
|
713
|
-
# }
|
|
714
646
|
else:
|
|
715
647
|
combined_schemas.append(
|
|
716
648
|
self.SCHEMA_OBJECT_TYPE.parse_obj(
|
|
@@ -728,7 +660,7 @@ class JsonSchemaParser(Parser):
|
|
|
728
660
|
obj,
|
|
729
661
|
singular_name=False,
|
|
730
662
|
)
|
|
731
|
-
common_path_keyword = f
|
|
663
|
+
common_path_keyword = f"{target_attribute_name}Common"
|
|
732
664
|
return [
|
|
733
665
|
self._parse_object_common_part(
|
|
734
666
|
name,
|
|
@@ -744,35 +676,27 @@ class JsonSchemaParser(Parser):
|
|
|
744
676
|
for i, d in enumerate(parsed_schemas)
|
|
745
677
|
]
|
|
746
678
|
|
|
747
|
-
def parse_any_of(
|
|
748
|
-
self
|
|
749
|
-
) -> List[DataType]:
|
|
750
|
-
return self.parse_combined_schema(name, obj, path, 'anyOf')
|
|
679
|
+
def parse_any_of(self, name: str, obj: JsonSchemaObject, path: list[str]) -> list[DataType]:
|
|
680
|
+
return self.parse_combined_schema(name, obj, path, "anyOf")
|
|
751
681
|
|
|
752
|
-
def parse_one_of(
|
|
753
|
-
self
|
|
754
|
-
) -> List[DataType]:
|
|
755
|
-
return self.parse_combined_schema(name, obj, path, 'oneOf')
|
|
682
|
+
def parse_one_of(self, name: str, obj: JsonSchemaObject, path: list[str]) -> list[DataType]:
|
|
683
|
+
return self.parse_combined_schema(name, obj, path, "oneOf")
|
|
756
684
|
|
|
757
|
-
def _parse_object_common_part(
|
|
685
|
+
def _parse_object_common_part( # noqa: PLR0913, PLR0917
|
|
758
686
|
self,
|
|
759
687
|
name: str,
|
|
760
688
|
obj: JsonSchemaObject,
|
|
761
|
-
path:
|
|
762
|
-
ignore_duplicate_model: bool,
|
|
763
|
-
fields:
|
|
764
|
-
base_classes:
|
|
765
|
-
required:
|
|
689
|
+
path: list[str],
|
|
690
|
+
ignore_duplicate_model: bool, # noqa: FBT001
|
|
691
|
+
fields: list[DataModelFieldBase],
|
|
692
|
+
base_classes: list[Reference],
|
|
693
|
+
required: list[str],
|
|
766
694
|
) -> DataType:
|
|
767
695
|
if obj.properties:
|
|
768
|
-
fields.extend(
|
|
769
|
-
self.parse_object_fields(obj, path, get_module_name(name, None))
|
|
770
|
-
)
|
|
696
|
+
fields.extend(self.parse_object_fields(obj, path, get_module_name(name, None)))
|
|
771
697
|
# ignore an undetected object
|
|
772
698
|
if ignore_duplicate_model and not fields and len(base_classes) == 1:
|
|
773
|
-
with self.model_resolver.current_base_path_context(
|
|
774
|
-
self.model_resolver._base_path
|
|
775
|
-
):
|
|
699
|
+
with self.model_resolver.current_base_path_context(self.model_resolver._base_path): # noqa: SLF001
|
|
776
700
|
self.model_resolver.delete(path)
|
|
777
701
|
return self.data_type(reference=base_classes[0])
|
|
778
702
|
if required:
|
|
@@ -789,16 +713,13 @@ class JsonSchemaParser(Parser):
|
|
|
789
713
|
if required_ in field_name_to_field:
|
|
790
714
|
field = field_name_to_field[required_]
|
|
791
715
|
if self.force_optional_for_required_fields or (
|
|
792
|
-
self.apply_default_values_for_required_fields
|
|
793
|
-
and field.has_default
|
|
716
|
+
self.apply_default_values_for_required_fields and field.has_default
|
|
794
717
|
):
|
|
795
718
|
continue
|
|
796
719
|
field.required = True
|
|
797
720
|
else:
|
|
798
721
|
fields.append(
|
|
799
|
-
self.data_model_field_type(
|
|
800
|
-
required=True, original_name=required_, data_type=DataType()
|
|
801
|
-
)
|
|
722
|
+
self.data_model_field_type(required=True, original_name=required_, data_type=DataType())
|
|
802
723
|
)
|
|
803
724
|
if self.use_title_as_name and obj.title: # pragma: no cover
|
|
804
725
|
name = obj.title
|
|
@@ -819,15 +740,15 @@ class JsonSchemaParser(Parser):
|
|
|
819
740
|
|
|
820
741
|
return self.data_type(reference=reference)
|
|
821
742
|
|
|
822
|
-
def _parse_all_of_item(
|
|
743
|
+
def _parse_all_of_item( # noqa: PLR0913, PLR0917
|
|
823
744
|
self,
|
|
824
745
|
name: str,
|
|
825
746
|
obj: JsonSchemaObject,
|
|
826
|
-
path:
|
|
827
|
-
fields:
|
|
828
|
-
base_classes:
|
|
829
|
-
required:
|
|
830
|
-
union_models:
|
|
747
|
+
path: list[str],
|
|
748
|
+
fields: list[DataModelFieldBase],
|
|
749
|
+
base_classes: list[Reference],
|
|
750
|
+
required: list[str],
|
|
751
|
+
union_models: list[Reference],
|
|
831
752
|
) -> None:
|
|
832
753
|
for all_of_item in obj.allOf:
|
|
833
754
|
if all_of_item.ref: # $ref
|
|
@@ -842,9 +763,8 @@ class JsonSchemaParser(Parser):
|
|
|
842
763
|
|
|
843
764
|
if object_fields:
|
|
844
765
|
fields.extend(object_fields)
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
required.extend(all_of_item.required)
|
|
766
|
+
elif all_of_item.required:
|
|
767
|
+
required.extend(all_of_item.required)
|
|
848
768
|
self._parse_all_of_item(
|
|
849
769
|
name,
|
|
850
770
|
all_of_item,
|
|
@@ -856,40 +776,31 @@ class JsonSchemaParser(Parser):
|
|
|
856
776
|
)
|
|
857
777
|
if all_of_item.anyOf:
|
|
858
778
|
self.model_resolver.add(path, name, class_name=True, loaded=True)
|
|
859
|
-
union_models.extend(
|
|
860
|
-
d.reference
|
|
861
|
-
for d in self.parse_any_of(name, all_of_item, path)
|
|
862
|
-
if d.reference
|
|
863
|
-
)
|
|
779
|
+
union_models.extend(d.reference for d in self.parse_any_of(name, all_of_item, path) if d.reference)
|
|
864
780
|
if all_of_item.oneOf:
|
|
865
781
|
self.model_resolver.add(path, name, class_name=True, loaded=True)
|
|
866
|
-
union_models.extend(
|
|
867
|
-
d.reference
|
|
868
|
-
for d in self.parse_one_of(name, all_of_item, path)
|
|
869
|
-
if d.reference
|
|
870
|
-
)
|
|
782
|
+
union_models.extend(d.reference for d in self.parse_one_of(name, all_of_item, path) if d.reference)
|
|
871
783
|
|
|
872
784
|
def parse_all_of(
|
|
873
785
|
self,
|
|
874
786
|
name: str,
|
|
875
787
|
obj: JsonSchemaObject,
|
|
876
|
-
path:
|
|
877
|
-
ignore_duplicate_model: bool = False,
|
|
788
|
+
path: list[str],
|
|
789
|
+
ignore_duplicate_model: bool = False, # noqa: FBT001, FBT002
|
|
878
790
|
) -> DataType:
|
|
879
791
|
if len(obj.allOf) == 1 and not obj.properties:
|
|
880
792
|
single_obj = obj.allOf[0]
|
|
881
|
-
if
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
)
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
)
|
|
793
|
+
if (
|
|
794
|
+
single_obj.ref
|
|
795
|
+
and single_obj.ref_type == JSONReference.LOCAL
|
|
796
|
+
and get_model_by_path(self.raw_obj, single_obj.ref[2:].split("/")).get("enum")
|
|
797
|
+
):
|
|
798
|
+
return self.get_ref_data_type(single_obj.ref)
|
|
799
|
+
fields: list[DataModelFieldBase] = []
|
|
800
|
+
base_classes: list[Reference] = []
|
|
801
|
+
required: list[str] = []
|
|
802
|
+
union_models: list[Reference] = []
|
|
803
|
+
self._parse_all_of_item(name, obj, path, fields, base_classes, required, union_models)
|
|
893
804
|
if not union_models:
|
|
894
805
|
return self._parse_object_common_part(
|
|
895
806
|
name, obj, path, ignore_duplicate_model, fields, base_classes, required
|
|
@@ -898,21 +809,22 @@ class JsonSchemaParser(Parser):
|
|
|
898
809
|
all_of_data_type = self._parse_object_common_part(
|
|
899
810
|
name,
|
|
900
811
|
obj,
|
|
901
|
-
get_special_path(
|
|
812
|
+
get_special_path("allOf", path),
|
|
902
813
|
ignore_duplicate_model,
|
|
903
814
|
fields,
|
|
904
815
|
base_classes,
|
|
905
816
|
required,
|
|
906
817
|
)
|
|
818
|
+
assert all_of_data_type.reference is not None
|
|
907
819
|
data_type = self.data_type(
|
|
908
820
|
data_types=[
|
|
909
821
|
self._parse_object_common_part(
|
|
910
822
|
name,
|
|
911
823
|
obj,
|
|
912
|
-
get_special_path(f
|
|
824
|
+
get_special_path(f"union_model-{index}", path),
|
|
913
825
|
ignore_duplicate_model,
|
|
914
826
|
[],
|
|
915
|
-
[union_model, all_of_data_type.reference],
|
|
827
|
+
[union_model, all_of_data_type.reference],
|
|
916
828
|
[],
|
|
917
829
|
)
|
|
918
830
|
for index, union_model in enumerate(union_models)
|
|
@@ -940,20 +852,21 @@ class JsonSchemaParser(Parser):
|
|
|
940
852
|
return self.data_type(reference=reference)
|
|
941
853
|
|
|
942
854
|
def parse_object_fields(
|
|
943
|
-
self,
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
855
|
+
self,
|
|
856
|
+
obj: JsonSchemaObject,
|
|
857
|
+
path: list[str],
|
|
858
|
+
module_name: Optional[str] = None, # noqa: UP045
|
|
859
|
+
) -> list[DataModelFieldBase]:
|
|
860
|
+
properties: dict[str, JsonSchemaObject | bool] = {} if obj.properties is None else obj.properties
|
|
861
|
+
requires: set[str] = {*()} if obj.required is None else {*obj.required}
|
|
862
|
+
fields: list[DataModelFieldBase] = []
|
|
863
|
+
|
|
864
|
+
exclude_field_names: set[str] = set()
|
|
952
865
|
for original_field_name, field in properties.items():
|
|
953
866
|
field_name, alias = self.model_resolver.get_valid_field_name_and_alias(
|
|
954
867
|
original_field_name, exclude_field_names
|
|
955
868
|
)
|
|
956
|
-
modular_name = f
|
|
869
|
+
modular_name = f"{module_name}.{field_name}" if module_name else field_name
|
|
957
870
|
|
|
958
871
|
exclude_field_names.add(field_name)
|
|
959
872
|
|
|
@@ -964,9 +877,7 @@ class JsonSchemaParser(Parser):
|
|
|
964
877
|
data_type=self.data_type_manager.get_data_type(
|
|
965
878
|
Types.any,
|
|
966
879
|
),
|
|
967
|
-
required=False
|
|
968
|
-
if self.force_optional_for_required_fields
|
|
969
|
-
else original_field_name in requires,
|
|
880
|
+
required=False if self.force_optional_for_required_fields else original_field_name in requires,
|
|
970
881
|
alias=alias,
|
|
971
882
|
strip_default_none=self.strip_default_none,
|
|
972
883
|
use_annotated=self.use_annotated,
|
|
@@ -1000,15 +911,16 @@ class JsonSchemaParser(Parser):
|
|
|
1000
911
|
self,
|
|
1001
912
|
name: str,
|
|
1002
913
|
obj: JsonSchemaObject,
|
|
1003
|
-
path:
|
|
1004
|
-
singular_name: bool = False,
|
|
1005
|
-
unique: bool = True,
|
|
914
|
+
path: list[str],
|
|
915
|
+
singular_name: bool = False, # noqa: FBT001, FBT002
|
|
916
|
+
unique: bool = True, # noqa: FBT001, FBT002
|
|
1006
917
|
) -> DataType:
|
|
1007
918
|
if not unique: # pragma: no cover
|
|
1008
919
|
warn(
|
|
1009
|
-
f
|
|
1010
|
-
f
|
|
1011
|
-
f
|
|
920
|
+
f"{self.__class__.__name__}.parse_object() ignore `unique` argument."
|
|
921
|
+
f"An object name must be unique."
|
|
922
|
+
f"This argument will be removed in a future version",
|
|
923
|
+
stacklevel=2,
|
|
1012
924
|
)
|
|
1013
925
|
if self.use_title_as_name and obj.title:
|
|
1014
926
|
name = obj.title
|
|
@@ -1037,7 +949,7 @@ class JsonSchemaParser(Parser):
|
|
|
1037
949
|
# TODO: Improve naming for nested ClassName
|
|
1038
950
|
name,
|
|
1039
951
|
obj.additionalProperties,
|
|
1040
|
-
[*path,
|
|
952
|
+
[*path, "additionalProperties"],
|
|
1041
953
|
)
|
|
1042
954
|
],
|
|
1043
955
|
is_dict=True,
|
|
@@ -1065,8 +977,8 @@ class JsonSchemaParser(Parser):
|
|
|
1065
977
|
def parse_pattern_properties(
|
|
1066
978
|
self,
|
|
1067
979
|
name: str,
|
|
1068
|
-
pattern_properties:
|
|
1069
|
-
path:
|
|
980
|
+
pattern_properties: dict[str, JsonSchemaObject],
|
|
981
|
+
path: list[str],
|
|
1070
982
|
) -> DataType:
|
|
1071
983
|
return self.data_type(
|
|
1072
984
|
data_types=[
|
|
@@ -1075,7 +987,7 @@ class JsonSchemaParser(Parser):
|
|
|
1075
987
|
self.parse_item(
|
|
1076
988
|
name,
|
|
1077
989
|
kv[1],
|
|
1078
|
-
get_special_path(f
|
|
990
|
+
get_special_path(f"patternProperties/{i}", path),
|
|
1079
991
|
)
|
|
1080
992
|
],
|
|
1081
993
|
is_dict=True,
|
|
@@ -1088,24 +1000,19 @@ class JsonSchemaParser(Parser):
|
|
|
1088
1000
|
],
|
|
1089
1001
|
)
|
|
1090
1002
|
|
|
1091
|
-
def parse_item(
|
|
1003
|
+
def parse_item( # noqa: PLR0911, PLR0912
|
|
1092
1004
|
self,
|
|
1093
1005
|
name: str,
|
|
1094
1006
|
item: JsonSchemaObject,
|
|
1095
|
-
path:
|
|
1096
|
-
singular_name: bool = False,
|
|
1097
|
-
parent:
|
|
1007
|
+
path: list[str],
|
|
1008
|
+
singular_name: bool = False, # noqa: FBT001, FBT002
|
|
1009
|
+
parent: JsonSchemaObject | None = None,
|
|
1098
1010
|
) -> DataType:
|
|
1099
1011
|
if self.use_title_as_name and item.title:
|
|
1100
1012
|
name = item.title
|
|
1101
1013
|
singular_name = False
|
|
1102
|
-
if (
|
|
1103
|
-
|
|
1104
|
-
and not item.enum
|
|
1105
|
-
and item.has_constraint
|
|
1106
|
-
and (parent.has_constraint or self.field_constraints)
|
|
1107
|
-
):
|
|
1108
|
-
root_type_path = get_special_path('array', path)
|
|
1014
|
+
if parent and not item.enum and item.has_constraint and (parent.has_constraint or self.field_constraints):
|
|
1015
|
+
root_type_path = get_special_path("array", path)
|
|
1109
1016
|
return self.parse_root_type(
|
|
1110
1017
|
self.model_resolver.add(
|
|
1111
1018
|
root_type_path,
|
|
@@ -1116,83 +1023,56 @@ class JsonSchemaParser(Parser):
|
|
|
1116
1023
|
item,
|
|
1117
1024
|
root_type_path,
|
|
1118
1025
|
)
|
|
1119
|
-
|
|
1026
|
+
if item.ref:
|
|
1120
1027
|
return self.get_ref_data_type(item.ref)
|
|
1121
|
-
|
|
1122
|
-
return self.data_type_manager.get_data_type_from_full_path(
|
|
1123
|
-
|
|
1124
|
-
)
|
|
1125
|
-
|
|
1126
|
-
return self.parse_array_fields(
|
|
1127
|
-
name, item, get_special_path('array', path)
|
|
1128
|
-
).data_type
|
|
1129
|
-
elif (
|
|
1130
|
-
item.discriminator
|
|
1131
|
-
and parent
|
|
1132
|
-
and parent.is_array
|
|
1133
|
-
and (item.oneOf or item.anyOf)
|
|
1134
|
-
):
|
|
1028
|
+
if item.custom_type_path:
|
|
1029
|
+
return self.data_type_manager.get_data_type_from_full_path(item.custom_type_path, is_custom_type=True)
|
|
1030
|
+
if item.is_array:
|
|
1031
|
+
return self.parse_array_fields(name, item, get_special_path("array", path)).data_type
|
|
1032
|
+
if item.discriminator and parent and parent.is_array and (item.oneOf or item.anyOf):
|
|
1135
1033
|
return self.parse_root_type(name, item, path)
|
|
1136
|
-
|
|
1137
|
-
return self.data_type(
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
)
|
|
1142
|
-
elif item.oneOf:
|
|
1143
|
-
return self.data_type(
|
|
1144
|
-
data_types=self.parse_one_of(
|
|
1145
|
-
name, item, get_special_path('oneOf', path)
|
|
1146
|
-
)
|
|
1147
|
-
)
|
|
1148
|
-
elif item.allOf:
|
|
1149
|
-
all_of_path = get_special_path('allOf', path)
|
|
1034
|
+
if item.anyOf:
|
|
1035
|
+
return self.data_type(data_types=self.parse_any_of(name, item, get_special_path("anyOf", path)))
|
|
1036
|
+
if item.oneOf:
|
|
1037
|
+
return self.data_type(data_types=self.parse_one_of(name, item, get_special_path("oneOf", path)))
|
|
1038
|
+
if item.allOf:
|
|
1039
|
+
all_of_path = get_special_path("allOf", path)
|
|
1150
1040
|
all_of_path = [self.model_resolver.resolve_ref(all_of_path)]
|
|
1151
1041
|
return self.parse_all_of(
|
|
1152
|
-
self.model_resolver.add(
|
|
1153
|
-
all_of_path, name, singular_name=singular_name, class_name=True
|
|
1154
|
-
).name,
|
|
1042
|
+
self.model_resolver.add(all_of_path, name, singular_name=singular_name, class_name=True).name,
|
|
1155
1043
|
item,
|
|
1156
1044
|
all_of_path,
|
|
1157
1045
|
ignore_duplicate_model=True,
|
|
1158
1046
|
)
|
|
1159
|
-
|
|
1160
|
-
object_path = get_special_path(
|
|
1047
|
+
if item.is_object or item.patternProperties:
|
|
1048
|
+
object_path = get_special_path("object", path)
|
|
1161
1049
|
if item.properties:
|
|
1162
|
-
return self.parse_object(
|
|
1163
|
-
|
|
1164
|
-
)
|
|
1165
|
-
elif item.patternProperties:
|
|
1050
|
+
return self.parse_object(name, item, object_path, singular_name=singular_name)
|
|
1051
|
+
if item.patternProperties:
|
|
1166
1052
|
# support only single key dict.
|
|
1167
|
-
return self.parse_pattern_properties(
|
|
1168
|
-
|
|
1169
|
-
)
|
|
1170
|
-
elif isinstance(item.additionalProperties, JsonSchemaObject):
|
|
1053
|
+
return self.parse_pattern_properties(name, item.patternProperties, object_path)
|
|
1054
|
+
if isinstance(item.additionalProperties, JsonSchemaObject):
|
|
1171
1055
|
return self.data_type(
|
|
1172
|
-
data_types=[
|
|
1173
|
-
self.parse_item(name, item.additionalProperties, object_path)
|
|
1174
|
-
],
|
|
1056
|
+
data_types=[self.parse_item(name, item.additionalProperties, object_path)],
|
|
1175
1057
|
is_dict=True,
|
|
1176
1058
|
)
|
|
1177
1059
|
return self.data_type_manager.get_data_type(
|
|
1178
1060
|
Types.object,
|
|
1179
1061
|
)
|
|
1180
|
-
|
|
1062
|
+
if item.enum:
|
|
1181
1063
|
if self.should_parse_enum_as_literal(item):
|
|
1182
1064
|
return self.parse_enum_as_literal(item)
|
|
1183
|
-
return self.parse_enum(
|
|
1184
|
-
name, item, get_special_path('enum', path), singular_name=singular_name
|
|
1185
|
-
)
|
|
1065
|
+
return self.parse_enum(name, item, get_special_path("enum", path), singular_name=singular_name)
|
|
1186
1066
|
return self.get_data_type(item)
|
|
1187
1067
|
|
|
1188
1068
|
def parse_list_item(
|
|
1189
1069
|
self,
|
|
1190
1070
|
name: str,
|
|
1191
|
-
target_items:
|
|
1192
|
-
path:
|
|
1071
|
+
target_items: list[JsonSchemaObject],
|
|
1072
|
+
path: list[str],
|
|
1193
1073
|
parent: JsonSchemaObject,
|
|
1194
|
-
singular_name: bool = True,
|
|
1195
|
-
) ->
|
|
1074
|
+
singular_name: bool = True, # noqa: FBT001, FBT002
|
|
1075
|
+
) -> list[DataType]:
|
|
1196
1076
|
return [
|
|
1197
1077
|
self.parse_item(
|
|
1198
1078
|
name,
|
|
@@ -1208,29 +1088,27 @@ class JsonSchemaParser(Parser):
|
|
|
1208
1088
|
self,
|
|
1209
1089
|
name: str,
|
|
1210
1090
|
obj: JsonSchemaObject,
|
|
1211
|
-
path:
|
|
1212
|
-
singular_name: bool = True,
|
|
1091
|
+
path: list[str],
|
|
1092
|
+
singular_name: bool = True, # noqa: FBT001, FBT002
|
|
1213
1093
|
) -> DataModelFieldBase:
|
|
1214
1094
|
if self.force_optional_for_required_fields:
|
|
1215
1095
|
required: bool = False
|
|
1216
|
-
nullable: Optional[bool] = None
|
|
1096
|
+
nullable: Optional[bool] = None # noqa: UP045
|
|
1217
1097
|
else:
|
|
1218
|
-
required = not (
|
|
1219
|
-
obj.has_default and self.apply_default_values_for_required_fields
|
|
1220
|
-
)
|
|
1098
|
+
required = not (obj.has_default and self.apply_default_values_for_required_fields)
|
|
1221
1099
|
if self.strict_nullable:
|
|
1222
1100
|
nullable = obj.nullable if obj.has_default or required else True
|
|
1223
1101
|
else:
|
|
1224
1102
|
required = not obj.nullable and required
|
|
1225
1103
|
nullable = None
|
|
1226
1104
|
if isinstance(obj.items, JsonSchemaObject):
|
|
1227
|
-
items:
|
|
1105
|
+
items: list[JsonSchemaObject] = [obj.items]
|
|
1228
1106
|
elif isinstance(obj.items, list):
|
|
1229
1107
|
items = obj.items
|
|
1230
1108
|
else:
|
|
1231
1109
|
items = []
|
|
1232
1110
|
|
|
1233
|
-
data_types:
|
|
1111
|
+
data_types: list[DataType] = [
|
|
1234
1112
|
self.data_type(
|
|
1235
1113
|
data_types=self.parse_list_item(
|
|
1236
1114
|
name,
|
|
@@ -1244,17 +1122,11 @@ class JsonSchemaParser(Parser):
|
|
|
1244
1122
|
]
|
|
1245
1123
|
# TODO: decide special path word for a combined data model.
|
|
1246
1124
|
if obj.allOf:
|
|
1247
|
-
data_types.append(
|
|
1248
|
-
self.parse_all_of(name, obj, get_special_path('allOf', path))
|
|
1249
|
-
)
|
|
1125
|
+
data_types.append(self.parse_all_of(name, obj, get_special_path("allOf", path)))
|
|
1250
1126
|
elif obj.is_object:
|
|
1251
|
-
data_types.append(
|
|
1252
|
-
self.parse_object(name, obj, get_special_path('object', path))
|
|
1253
|
-
)
|
|
1127
|
+
data_types.append(self.parse_object(name, obj, get_special_path("object", path)))
|
|
1254
1128
|
if obj.enum:
|
|
1255
|
-
data_types.append(
|
|
1256
|
-
self.parse_enum(name, obj, get_special_path('enum', path))
|
|
1257
|
-
)
|
|
1129
|
+
data_types.append(self.parse_enum(name, obj, get_special_path("enum", path)))
|
|
1258
1130
|
return self.data_model_field_type(
|
|
1259
1131
|
data_type=self.data_type(data_types=data_types),
|
|
1260
1132
|
default=obj.default,
|
|
@@ -1273,24 +1145,20 @@ class JsonSchemaParser(Parser):
|
|
|
1273
1145
|
self,
|
|
1274
1146
|
name: str,
|
|
1275
1147
|
obj: JsonSchemaObject,
|
|
1276
|
-
path:
|
|
1277
|
-
original_name:
|
|
1148
|
+
path: list[str],
|
|
1149
|
+
original_name: str | None = None,
|
|
1278
1150
|
) -> DataType:
|
|
1279
1151
|
if self.use_title_as_name and obj.title:
|
|
1280
1152
|
name = obj.title
|
|
1281
1153
|
reference = self.model_resolver.add(path, name, loaded=True, class_name=True)
|
|
1282
1154
|
field = self.parse_array_fields(original_name or name, obj, [*path, name])
|
|
1283
1155
|
|
|
1284
|
-
if reference in [
|
|
1285
|
-
d.reference for d in field.data_type.all_data_types if d.reference
|
|
1286
|
-
]:
|
|
1156
|
+
if reference in [d.reference for d in field.data_type.all_data_types if d.reference]:
|
|
1287
1157
|
# self-reference
|
|
1288
1158
|
field = self.data_model_field_type(
|
|
1289
1159
|
data_type=self.data_type(
|
|
1290
1160
|
data_types=[
|
|
1291
|
-
self.data_type(
|
|
1292
|
-
data_types=field.data_type.data_types[1:], is_list=True
|
|
1293
|
-
),
|
|
1161
|
+
self.data_type(data_types=field.data_type.data_types[1:], is_list=True),
|
|
1294
1162
|
*field.data_type.data_types[1:],
|
|
1295
1163
|
]
|
|
1296
1164
|
),
|
|
@@ -1319,13 +1187,13 @@ class JsonSchemaParser(Parser):
|
|
|
1319
1187
|
self.results.append(data_model_root)
|
|
1320
1188
|
return self.data_type(reference=reference)
|
|
1321
1189
|
|
|
1322
|
-
def parse_root_type(
|
|
1190
|
+
def parse_root_type( # noqa: PLR0912
|
|
1323
1191
|
self,
|
|
1324
1192
|
name: str,
|
|
1325
1193
|
obj: JsonSchemaObject,
|
|
1326
|
-
path:
|
|
1194
|
+
path: list[str],
|
|
1327
1195
|
) -> DataType:
|
|
1328
|
-
reference:
|
|
1196
|
+
reference: Reference | None = None
|
|
1329
1197
|
if obj.ref:
|
|
1330
1198
|
data_type: DataType = self.get_ref_data_type(obj.ref)
|
|
1331
1199
|
elif obj.custom_type_path:
|
|
@@ -1334,20 +1202,14 @@ class JsonSchemaParser(Parser):
|
|
|
1334
1202
|
) # pragma: no cover
|
|
1335
1203
|
elif obj.is_array:
|
|
1336
1204
|
data_type = self.parse_array_fields(
|
|
1337
|
-
name, obj, get_special_path(
|
|
1205
|
+
name, obj, get_special_path("array", path)
|
|
1338
1206
|
).data_type # pragma: no cover
|
|
1339
1207
|
elif obj.anyOf or obj.oneOf:
|
|
1340
|
-
reference = self.model_resolver.add(
|
|
1341
|
-
path, name, loaded=True, class_name=True
|
|
1342
|
-
)
|
|
1208
|
+
reference = self.model_resolver.add(path, name, loaded=True, class_name=True)
|
|
1343
1209
|
if obj.anyOf:
|
|
1344
|
-
data_types:
|
|
1345
|
-
name, obj, get_special_path('anyOf', path)
|
|
1346
|
-
)
|
|
1210
|
+
data_types: list[DataType] = self.parse_any_of(name, obj, get_special_path("anyOf", path))
|
|
1347
1211
|
else:
|
|
1348
|
-
data_types = self.parse_one_of(
|
|
1349
|
-
name, obj, get_special_path('oneOf', path)
|
|
1350
|
-
)
|
|
1212
|
+
data_types = self.parse_one_of(name, obj, get_special_path("oneOf", path))
|
|
1351
1213
|
|
|
1352
1214
|
if len(data_types) > 1: # pragma: no cover
|
|
1353
1215
|
data_type = self.data_type(data_types=data_types)
|
|
@@ -1371,15 +1233,11 @@ class JsonSchemaParser(Parser):
|
|
|
1371
1233
|
if self.force_optional_for_required_fields:
|
|
1372
1234
|
required: bool = False
|
|
1373
1235
|
else:
|
|
1374
|
-
required = not obj.nullable and not (
|
|
1375
|
-
obj.has_default and self.apply_default_values_for_required_fields
|
|
1376
|
-
)
|
|
1236
|
+
required = not obj.nullable and not (obj.has_default and self.apply_default_values_for_required_fields)
|
|
1377
1237
|
if self.use_title_as_name and obj.title:
|
|
1378
1238
|
name = obj.title
|
|
1379
1239
|
if not reference:
|
|
1380
|
-
reference = self.model_resolver.add(
|
|
1381
|
-
path, name, loaded=True, class_name=True
|
|
1382
|
-
)
|
|
1240
|
+
reference = self.model_resolver.add(path, name, loaded=True, class_name=True)
|
|
1383
1241
|
self.set_title(name, obj)
|
|
1384
1242
|
self.set_additional_properties(name, obj)
|
|
1385
1243
|
data_model_root_type = self.data_model_root_type(
|
|
@@ -1415,19 +1273,20 @@ class JsonSchemaParser(Parser):
|
|
|
1415
1273
|
self,
|
|
1416
1274
|
name: str,
|
|
1417
1275
|
obj: JsonSchemaObject,
|
|
1418
|
-
path:
|
|
1419
|
-
singular_name: bool = False,
|
|
1420
|
-
unique: bool = True,
|
|
1276
|
+
path: list[str],
|
|
1277
|
+
singular_name: bool = False, # noqa: FBT001, FBT002
|
|
1278
|
+
unique: bool = True, # noqa: FBT001, FBT002
|
|
1421
1279
|
) -> DataType:
|
|
1422
1280
|
if not unique: # pragma: no cover
|
|
1423
1281
|
warn(
|
|
1424
|
-
f
|
|
1425
|
-
f
|
|
1426
|
-
f
|
|
1282
|
+
f"{self.__class__.__name__}.parse_enum() ignore `unique` argument."
|
|
1283
|
+
f"An object name must be unique."
|
|
1284
|
+
f"This argument will be removed in a future version",
|
|
1285
|
+
stacklevel=2,
|
|
1427
1286
|
)
|
|
1428
|
-
enum_fields:
|
|
1287
|
+
enum_fields: list[DataModelFieldBase] = []
|
|
1429
1288
|
|
|
1430
|
-
if None in obj.enum and obj.type ==
|
|
1289
|
+
if None in obj.enum and obj.type == "string":
|
|
1431
1290
|
# Nullable is valid in only OpenAPI
|
|
1432
1291
|
nullable: bool = True
|
|
1433
1292
|
enum_times = [e for e in obj.enum if e is not None]
|
|
@@ -1435,30 +1294,19 @@ class JsonSchemaParser(Parser):
|
|
|
1435
1294
|
enum_times = obj.enum
|
|
1436
1295
|
nullable = False
|
|
1437
1296
|
|
|
1438
|
-
exclude_field_names:
|
|
1297
|
+
exclude_field_names: set[str] = set()
|
|
1439
1298
|
|
|
1440
1299
|
for i, enum_part in enumerate(enum_times):
|
|
1441
|
-
if obj.type ==
|
|
1442
|
-
default = (
|
|
1443
|
-
|
|
1444
|
-
if isinstance(enum_part, str)
|
|
1445
|
-
else enum_part
|
|
1446
|
-
)
|
|
1447
|
-
if obj.x_enum_varnames:
|
|
1448
|
-
field_name = obj.x_enum_varnames[i]
|
|
1449
|
-
else:
|
|
1450
|
-
field_name = str(enum_part)
|
|
1300
|
+
if obj.type == "string" or isinstance(enum_part, str):
|
|
1301
|
+
default = f"'{enum_part.translate(escape_characters)}'" if isinstance(enum_part, str) else enum_part
|
|
1302
|
+
field_name = obj.x_enum_varnames[i] if obj.x_enum_varnames else str(enum_part)
|
|
1451
1303
|
else:
|
|
1452
1304
|
default = enum_part
|
|
1453
1305
|
if obj.x_enum_varnames:
|
|
1454
1306
|
field_name = obj.x_enum_varnames[i]
|
|
1455
1307
|
else:
|
|
1456
|
-
prefix = (
|
|
1457
|
-
|
|
1458
|
-
if isinstance(obj.type, str)
|
|
1459
|
-
else type(enum_part).__name__
|
|
1460
|
-
)
|
|
1461
|
-
field_name = f'{prefix}_{enum_part}'
|
|
1308
|
+
prefix = obj.type if isinstance(obj.type, str) else type(enum_part).__name__
|
|
1309
|
+
field_name = f"{prefix}_{enum_part}"
|
|
1462
1310
|
field_name = self.model_resolver.get_valid_field_name(
|
|
1463
1311
|
field_name, excludes=exclude_field_names, model_type=ModelType.ENUM
|
|
1464
1312
|
)
|
|
@@ -1485,9 +1333,7 @@ class JsonSchemaParser(Parser):
|
|
|
1485
1333
|
path=self.current_source_path,
|
|
1486
1334
|
description=obj.description if self.use_schema_description else None,
|
|
1487
1335
|
custom_template_dir=self.custom_template_dir,
|
|
1488
|
-
type_=_get_type(obj.type, obj.format)
|
|
1489
|
-
if self.use_subclass_enum and isinstance(obj.type, str)
|
|
1490
|
-
else None,
|
|
1336
|
+
type_=_get_type(obj.type, obj.format) if self.use_subclass_enum and isinstance(obj.type, str) else None,
|
|
1491
1337
|
default=obj.default if obj.has_default else UNDEFINED,
|
|
1492
1338
|
)
|
|
1493
1339
|
self.results.append(enum)
|
|
@@ -1500,7 +1346,7 @@ class JsonSchemaParser(Parser):
|
|
|
1500
1346
|
name,
|
|
1501
1347
|
class_name=True,
|
|
1502
1348
|
singular_name=singular_name,
|
|
1503
|
-
singular_name_suffix=
|
|
1349
|
+
singular_name_suffix="Enum",
|
|
1504
1350
|
loaded=True,
|
|
1505
1351
|
)
|
|
1506
1352
|
|
|
@@ -1508,11 +1354,11 @@ class JsonSchemaParser(Parser):
|
|
|
1508
1354
|
return create_enum(reference)
|
|
1509
1355
|
|
|
1510
1356
|
enum_reference = self.model_resolver.add(
|
|
1511
|
-
[*path,
|
|
1512
|
-
f
|
|
1357
|
+
[*path, "Enum"],
|
|
1358
|
+
f"{reference.name}Enum",
|
|
1513
1359
|
class_name=True,
|
|
1514
1360
|
singular_name=singular_name,
|
|
1515
|
-
singular_name_suffix=
|
|
1361
|
+
singular_name_suffix="Enum",
|
|
1516
1362
|
loaded=True,
|
|
1517
1363
|
)
|
|
1518
1364
|
|
|
@@ -1542,19 +1388,19 @@ class JsonSchemaParser(Parser):
|
|
|
1542
1388
|
self.results.append(data_model_root_type)
|
|
1543
1389
|
return self.data_type(reference=reference)
|
|
1544
1390
|
|
|
1545
|
-
def _get_ref_body(self, resolved_ref: str) ->
|
|
1391
|
+
def _get_ref_body(self, resolved_ref: str) -> dict[Any, Any]:
|
|
1546
1392
|
if is_url(resolved_ref):
|
|
1547
1393
|
return self._get_ref_body_from_url(resolved_ref)
|
|
1548
1394
|
return self._get_ref_body_from_remote(resolved_ref)
|
|
1549
1395
|
|
|
1550
|
-
def _get_ref_body_from_url(self, ref: str) ->
|
|
1551
|
-
# URL Reference
|
|
1396
|
+
def _get_ref_body_from_url(self, ref: str) -> dict[Any, Any]:
|
|
1397
|
+
# URL Reference: $ref: 'http://path/to/your/resource' Uses the whole document located on the different server.
|
|
1552
1398
|
return self.remote_object_cache.get_or_put(
|
|
1553
1399
|
ref, default_factory=lambda key: load_yaml(self._get_text_from_url(key))
|
|
1554
1400
|
)
|
|
1555
1401
|
|
|
1556
|
-
def _get_ref_body_from_remote(self, resolved_ref: str) ->
|
|
1557
|
-
# Remote Reference
|
|
1402
|
+
def _get_ref_body_from_remote(self, resolved_ref: str) -> dict[Any, Any]:
|
|
1403
|
+
# Remote Reference: $ref: 'document.json' Uses the whole document located on the same server and in
|
|
1558
1404
|
# the same location. TODO treat edge case
|
|
1559
1405
|
full_path = self.base_path / resolved_ref
|
|
1560
1406
|
|
|
@@ -1571,46 +1417,46 @@ class JsonSchemaParser(Parser):
|
|
|
1571
1417
|
# https://swagger.io/docs/specification/using-ref/
|
|
1572
1418
|
ref = self.model_resolver.resolve_ref(object_ref)
|
|
1573
1419
|
if get_ref_type(object_ref) == JSONReference.LOCAL:
|
|
1574
|
-
# Local Reference
|
|
1575
|
-
self.reserved_refs[tuple(self.model_resolver.current_root)].add(ref)
|
|
1420
|
+
# Local Reference: $ref: '#/definitions/myElement'
|
|
1421
|
+
self.reserved_refs[tuple(self.model_resolver.current_root)].add(ref)
|
|
1576
1422
|
return reference
|
|
1577
|
-
|
|
1578
|
-
self.reserved_refs[tuple(ref.split(
|
|
1423
|
+
if self.model_resolver.is_after_load(ref):
|
|
1424
|
+
self.reserved_refs[tuple(ref.split("#")[0].split("/"))].add(ref)
|
|
1579
1425
|
return reference
|
|
1580
1426
|
|
|
1581
1427
|
if is_url(ref):
|
|
1582
|
-
relative_path, object_path = ref.split(
|
|
1428
|
+
relative_path, object_path = ref.split("#")
|
|
1583
1429
|
relative_paths = [relative_path]
|
|
1584
1430
|
base_path = None
|
|
1585
1431
|
else:
|
|
1586
1432
|
if self.model_resolver.is_external_root_ref(ref):
|
|
1587
|
-
relative_path, object_path = ref[:-1],
|
|
1433
|
+
relative_path, object_path = ref[:-1], ""
|
|
1588
1434
|
else:
|
|
1589
|
-
relative_path, object_path = ref.split(
|
|
1590
|
-
relative_paths = relative_path.split(
|
|
1435
|
+
relative_path, object_path = ref.split("#")
|
|
1436
|
+
relative_paths = relative_path.split("/")
|
|
1591
1437
|
base_path = Path(*relative_paths).parent
|
|
1592
|
-
with
|
|
1593
|
-
base_path
|
|
1594
|
-
|
|
1438
|
+
with (
|
|
1439
|
+
self.model_resolver.current_base_path_context(base_path),
|
|
1440
|
+
self.model_resolver.base_url_context(relative_path),
|
|
1441
|
+
):
|
|
1595
1442
|
self._parse_file(
|
|
1596
1443
|
self._get_ref_body(relative_path),
|
|
1597
1444
|
self.model_resolver.add_ref(ref, resolved=True).name,
|
|
1598
1445
|
relative_paths,
|
|
1599
|
-
object_path.split(
|
|
1446
|
+
object_path.split("/") if object_path else None,
|
|
1600
1447
|
)
|
|
1601
1448
|
reference.loaded = True
|
|
1602
1449
|
return reference
|
|
1603
1450
|
|
|
1604
|
-
def parse_ref(self, obj: JsonSchemaObject, path:
|
|
1451
|
+
def parse_ref(self, obj: JsonSchemaObject, path: list[str]) -> None: # noqa: PLR0912
|
|
1605
1452
|
if obj.ref:
|
|
1606
1453
|
self.resolve_ref(obj.ref)
|
|
1607
1454
|
if obj.items:
|
|
1608
1455
|
if isinstance(obj.items, JsonSchemaObject):
|
|
1609
1456
|
self.parse_ref(obj.items, path)
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
self.parse_ref(item, path)
|
|
1457
|
+
elif isinstance(obj.items, list):
|
|
1458
|
+
for item in obj.items:
|
|
1459
|
+
self.parse_ref(item, path)
|
|
1614
1460
|
if isinstance(obj.additionalProperties, JsonSchemaObject):
|
|
1615
1461
|
self.parse_ref(obj.additionalProperties, path)
|
|
1616
1462
|
if obj.patternProperties:
|
|
@@ -1627,16 +1473,15 @@ class JsonSchemaParser(Parser):
|
|
|
1627
1473
|
if isinstance(property_value, JsonSchemaObject):
|
|
1628
1474
|
self.parse_ref(property_value, path)
|
|
1629
1475
|
|
|
1630
|
-
def parse_id(self, obj: JsonSchemaObject, path:
|
|
1476
|
+
def parse_id(self, obj: JsonSchemaObject, path: list[str]) -> None: # noqa: PLR0912
|
|
1631
1477
|
if obj.id:
|
|
1632
1478
|
self.model_resolver.add_id(obj.id, path)
|
|
1633
1479
|
if obj.items:
|
|
1634
1480
|
if isinstance(obj.items, JsonSchemaObject):
|
|
1635
1481
|
self.parse_id(obj.items, path)
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
self.parse_id(item, path)
|
|
1482
|
+
elif isinstance(obj.items, list):
|
|
1483
|
+
for item in obj.items:
|
|
1484
|
+
self.parse_id(item, path)
|
|
1640
1485
|
if isinstance(obj.additionalProperties, JsonSchemaObject):
|
|
1641
1486
|
self.parse_id(obj.additionalProperties, path)
|
|
1642
1487
|
if obj.patternProperties:
|
|
@@ -1652,18 +1497,18 @@ class JsonSchemaParser(Parser):
|
|
|
1652
1497
|
self.parse_id(property_value, path)
|
|
1653
1498
|
|
|
1654
1499
|
@contextmanager
|
|
1655
|
-
def root_id_context(self, root_raw:
|
|
1656
|
-
root_id:
|
|
1657
|
-
previous_root_id:
|
|
1658
|
-
self.root_id = root_id
|
|
1500
|
+
def root_id_context(self, root_raw: dict[str, Any]) -> Generator[None, None, None]:
|
|
1501
|
+
root_id: str | None = root_raw.get("$id")
|
|
1502
|
+
previous_root_id: str | None = self.root_id
|
|
1503
|
+
self.root_id = root_id or None
|
|
1659
1504
|
yield
|
|
1660
1505
|
self.root_id = previous_root_id
|
|
1661
1506
|
|
|
1662
1507
|
def parse_raw_obj(
|
|
1663
1508
|
self,
|
|
1664
1509
|
name: str,
|
|
1665
|
-
raw:
|
|
1666
|
-
path:
|
|
1510
|
+
raw: dict[str, Any],
|
|
1511
|
+
path: list[str],
|
|
1667
1512
|
) -> None:
|
|
1668
1513
|
self.parse_obj(name, self.SCHEMA_OBJECT_TYPE.parse_obj(raw), path)
|
|
1669
1514
|
|
|
@@ -1671,7 +1516,7 @@ class JsonSchemaParser(Parser):
|
|
|
1671
1516
|
self,
|
|
1672
1517
|
name: str,
|
|
1673
1518
|
obj: JsonSchemaObject,
|
|
1674
|
-
path:
|
|
1519
|
+
path: list[str],
|
|
1675
1520
|
) -> None:
|
|
1676
1521
|
if obj.is_array:
|
|
1677
1522
|
self.parse_array(name, obj, path)
|
|
@@ -1685,7 +1530,7 @@ class JsonSchemaParser(Parser):
|
|
|
1685
1530
|
self.parse_object(name, obj, path)
|
|
1686
1531
|
elif obj.patternProperties:
|
|
1687
1532
|
self.parse_root_type(name, obj, path)
|
|
1688
|
-
elif obj.type ==
|
|
1533
|
+
elif obj.type == "object":
|
|
1689
1534
|
self.parse_object(name, obj, path)
|
|
1690
1535
|
elif obj.enum and not self.should_parse_enum_as_literal(obj):
|
|
1691
1536
|
self.parse_enum(name, obj, path)
|
|
@@ -1693,14 +1538,11 @@ class JsonSchemaParser(Parser):
|
|
|
1693
1538
|
self.parse_root_type(name, obj, path)
|
|
1694
1539
|
self.parse_ref(obj, path)
|
|
1695
1540
|
|
|
1696
|
-
def _get_context_source_path_parts(self) -> Iterator[
|
|
1697
|
-
if isinstance(self.source, list) or (
|
|
1698
|
-
isinstance(self.source, Path) and self.source.is_dir()
|
|
1699
|
-
):
|
|
1541
|
+
def _get_context_source_path_parts(self) -> Iterator[tuple[Source, list[str]]]:
|
|
1542
|
+
if isinstance(self.source, list) or (isinstance(self.source, Path) and self.source.is_dir()):
|
|
1700
1543
|
self.current_source_path = Path()
|
|
1701
1544
|
self.model_resolver.after_load_files = {
|
|
1702
|
-
self.base_path.joinpath(s.path).resolve().as_posix()
|
|
1703
|
-
for s in self.iter_source
|
|
1545
|
+
self.base_path.joinpath(s.path).resolve().as_posix() for s in self.iter_source
|
|
1704
1546
|
}
|
|
1705
1547
|
|
|
1706
1548
|
for source in self.iter_source:
|
|
@@ -1710,25 +1552,26 @@ class JsonSchemaParser(Parser):
|
|
|
1710
1552
|
path_parts = list(source.path.parts)
|
|
1711
1553
|
if self.current_source_path is not None:
|
|
1712
1554
|
self.current_source_path = source.path
|
|
1713
|
-
with
|
|
1714
|
-
source.path.parent
|
|
1715
|
-
|
|
1555
|
+
with (
|
|
1556
|
+
self.model_resolver.current_base_path_context(source.path.parent),
|
|
1557
|
+
self.model_resolver.current_root_context(path_parts),
|
|
1558
|
+
):
|
|
1716
1559
|
yield source, path_parts
|
|
1717
1560
|
|
|
1718
1561
|
def parse_raw(self) -> None:
|
|
1719
1562
|
for source, path_parts in self._get_context_source_path_parts():
|
|
1720
1563
|
self.raw_obj = load_yaml(source.text)
|
|
1721
1564
|
if self.raw_obj is None: # pragma: no cover
|
|
1722
|
-
warn(f
|
|
1565
|
+
warn(f"{source.path} is empty. Skipping this file", stacklevel=2)
|
|
1723
1566
|
continue
|
|
1724
1567
|
if self.custom_class_name_generator:
|
|
1725
|
-
obj_name = self.raw_obj.get(
|
|
1568
|
+
obj_name = self.raw_obj.get("title", "Model")
|
|
1726
1569
|
else:
|
|
1727
1570
|
if self.class_name:
|
|
1728
1571
|
obj_name = self.class_name
|
|
1729
1572
|
else:
|
|
1730
1573
|
# backward compatible
|
|
1731
|
-
obj_name = self.raw_obj.get(
|
|
1574
|
+
obj_name = self.raw_obj.get("title", "Model")
|
|
1732
1575
|
if not self.model_resolver.validate_name(obj_name):
|
|
1733
1576
|
obj_name = title_to_class_name(obj_name)
|
|
1734
1577
|
if not self.model_resolver.validate_name(obj_name):
|
|
@@ -1741,15 +1584,16 @@ class JsonSchemaParser(Parser):
|
|
|
1741
1584
|
model_count: int = len(self.results)
|
|
1742
1585
|
for source in self.iter_source:
|
|
1743
1586
|
path_parts = list(source.path.parts)
|
|
1744
|
-
reserved_refs = self.reserved_refs.get(tuple(path_parts))
|
|
1587
|
+
reserved_refs = self.reserved_refs.get(tuple(path_parts))
|
|
1745
1588
|
if not reserved_refs:
|
|
1746
1589
|
continue
|
|
1747
1590
|
if self.current_source_path is not None:
|
|
1748
1591
|
self.current_source_path = source.path
|
|
1749
1592
|
|
|
1750
|
-
with
|
|
1751
|
-
source.path.parent
|
|
1752
|
-
|
|
1593
|
+
with (
|
|
1594
|
+
self.model_resolver.current_base_path_context(source.path.parent),
|
|
1595
|
+
self.model_resolver.current_root_context(path_parts),
|
|
1596
|
+
):
|
|
1753
1597
|
for reserved_ref in sorted(reserved_refs):
|
|
1754
1598
|
if self.model_resolver.add_ref(reserved_ref, resolved=True).loaded:
|
|
1755
1599
|
continue
|
|
@@ -1761,45 +1605,36 @@ class JsonSchemaParser(Parser):
|
|
|
1761
1605
|
# New model have been generated. It try to resolve json pointer again.
|
|
1762
1606
|
self._resolve_unparsed_json_pointer()
|
|
1763
1607
|
|
|
1764
|
-
def parse_json_pointer(
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
path = ref.split('#', 1)[-1]
|
|
1768
|
-
if path[0] == '/': # pragma: no cover
|
|
1608
|
+
def parse_json_pointer(self, raw: dict[str, Any], ref: str, path_parts: list[str]) -> None:
|
|
1609
|
+
path = ref.split("#", 1)[-1]
|
|
1610
|
+
if path[0] == "/": # pragma: no cover
|
|
1769
1611
|
path = path[1:]
|
|
1770
|
-
object_paths = path.split(
|
|
1612
|
+
object_paths = path.split("/")
|
|
1771
1613
|
models = get_model_by_path(raw, object_paths)
|
|
1772
1614
|
model_name = object_paths[-1]
|
|
1773
1615
|
|
|
1774
|
-
self.parse_raw_obj(
|
|
1775
|
-
model_name, models, [*path_parts, f'#/{object_paths[0]}', *object_paths[1:]]
|
|
1776
|
-
)
|
|
1616
|
+
self.parse_raw_obj(model_name, models, [*path_parts, f"#/{object_paths[0]}", *object_paths[1:]])
|
|
1777
1617
|
|
|
1778
|
-
def _parse_file(
|
|
1618
|
+
def _parse_file( # noqa: PLR0912
|
|
1779
1619
|
self,
|
|
1780
|
-
raw:
|
|
1620
|
+
raw: dict[str, Any],
|
|
1781
1621
|
obj_name: str,
|
|
1782
|
-
path_parts:
|
|
1783
|
-
object_paths:
|
|
1622
|
+
path_parts: list[str],
|
|
1623
|
+
object_paths: list[str] | None = None,
|
|
1784
1624
|
) -> None:
|
|
1785
1625
|
object_paths = [o for o in object_paths or [] if o]
|
|
1786
|
-
if object_paths
|
|
1787
|
-
path = [*path_parts, f'#/{object_paths[0]}', *object_paths[1:]]
|
|
1788
|
-
else:
|
|
1789
|
-
path = path_parts
|
|
1626
|
+
path = [*path_parts, f"#/{object_paths[0]}", *object_paths[1:]] if object_paths else path_parts
|
|
1790
1627
|
with self.model_resolver.current_root_context(path_parts):
|
|
1791
|
-
obj_name = self.model_resolver.add(
|
|
1792
|
-
path, obj_name, unique=False, class_name=True
|
|
1793
|
-
).name
|
|
1628
|
+
obj_name = self.model_resolver.add(path, obj_name, unique=False, class_name=True).name
|
|
1794
1629
|
with self.root_id_context(raw):
|
|
1795
1630
|
# Some jsonschema docs include attribute self to have include version details
|
|
1796
|
-
raw.pop(
|
|
1631
|
+
raw.pop("self", None)
|
|
1797
1632
|
# parse $id before parsing $ref
|
|
1798
1633
|
root_obj = self.SCHEMA_OBJECT_TYPE.parse_obj(raw)
|
|
1799
1634
|
self.parse_id(root_obj, path_parts)
|
|
1800
|
-
definitions:
|
|
1801
|
-
|
|
1802
|
-
for
|
|
1635
|
+
definitions: dict[Any, Any] | None = None
|
|
1636
|
+
_schema_path = ""
|
|
1637
|
+
for _schema_path, split_schema_path in self.schema_paths:
|
|
1803
1638
|
try:
|
|
1804
1639
|
definitions = get_model_by_path(raw, split_schema_path)
|
|
1805
1640
|
if definitions:
|
|
@@ -1811,18 +1646,16 @@ class JsonSchemaParser(Parser):
|
|
|
1811
1646
|
|
|
1812
1647
|
for key, model in definitions.items():
|
|
1813
1648
|
obj = self.SCHEMA_OBJECT_TYPE.parse_obj(model)
|
|
1814
|
-
self.parse_id(obj, [*path_parts,
|
|
1649
|
+
self.parse_id(obj, [*path_parts, _schema_path, key])
|
|
1815
1650
|
|
|
1816
1651
|
if object_paths:
|
|
1817
1652
|
models = get_model_by_path(raw, object_paths)
|
|
1818
1653
|
model_name = object_paths[-1]
|
|
1819
|
-
self.parse_obj(
|
|
1820
|
-
model_name, self.SCHEMA_OBJECT_TYPE.parse_obj(models), path
|
|
1821
|
-
)
|
|
1654
|
+
self.parse_obj(model_name, self.SCHEMA_OBJECT_TYPE.parse_obj(models), path)
|
|
1822
1655
|
else:
|
|
1823
|
-
self.parse_obj(obj_name, root_obj, path_parts or [
|
|
1656
|
+
self.parse_obj(obj_name, root_obj, path_parts or ["#"])
|
|
1824
1657
|
for key, model in definitions.items():
|
|
1825
|
-
path = [*path_parts,
|
|
1658
|
+
path = [*path_parts, _schema_path, key]
|
|
1826
1659
|
reference = self.model_resolver.get(path)
|
|
1827
1660
|
if not reference or not reference.loaded:
|
|
1828
1661
|
self.parse_raw_obj(key, model, path)
|
|
@@ -1834,13 +1667,11 @@ class JsonSchemaParser(Parser):
|
|
|
1834
1667
|
reference = self.model_resolver.get(reserved_path)
|
|
1835
1668
|
if not reference or reference.loaded:
|
|
1836
1669
|
continue
|
|
1837
|
-
object_paths = reserved_path.split(
|
|
1838
|
-
path = reserved_path.split(
|
|
1670
|
+
object_paths = reserved_path.split("#/", 1)[-1].split("/")
|
|
1671
|
+
path = reserved_path.split("/")
|
|
1839
1672
|
models = get_model_by_path(raw, object_paths)
|
|
1840
1673
|
model_name = object_paths[-1]
|
|
1841
|
-
self.parse_obj(
|
|
1842
|
-
model_name, self.SCHEMA_OBJECT_TYPE.parse_obj(models), path
|
|
1843
|
-
)
|
|
1674
|
+
self.parse_obj(model_name, self.SCHEMA_OBJECT_TYPE.parse_obj(models), path)
|
|
1844
1675
|
previous_reserved_refs = reserved_refs
|
|
1845
1676
|
reserved_refs = set(self.reserved_refs.get(key) or [])
|
|
1846
1677
|
if previous_reserved_refs == reserved_refs:
|