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.

Files changed (43) hide show
  1. datamodel_code_generator/__init__.py +168 -196
  2. datamodel_code_generator/__main__.py +146 -189
  3. datamodel_code_generator/arguments.py +227 -230
  4. datamodel_code_generator/format.py +77 -129
  5. datamodel_code_generator/http.py +12 -10
  6. datamodel_code_generator/imports.py +59 -65
  7. datamodel_code_generator/model/__init__.py +28 -31
  8. datamodel_code_generator/model/base.py +100 -144
  9. datamodel_code_generator/model/dataclass.py +62 -70
  10. datamodel_code_generator/model/enum.py +34 -30
  11. datamodel_code_generator/model/imports.py +13 -11
  12. datamodel_code_generator/model/msgspec.py +116 -138
  13. datamodel_code_generator/model/pydantic/__init__.py +18 -28
  14. datamodel_code_generator/model/pydantic/base_model.py +121 -140
  15. datamodel_code_generator/model/pydantic/custom_root_type.py +2 -2
  16. datamodel_code_generator/model/pydantic/dataclass.py +6 -4
  17. datamodel_code_generator/model/pydantic/imports.py +35 -33
  18. datamodel_code_generator/model/pydantic/types.py +91 -119
  19. datamodel_code_generator/model/pydantic_v2/__init__.py +21 -18
  20. datamodel_code_generator/model/pydantic_v2/base_model.py +118 -127
  21. datamodel_code_generator/model/pydantic_v2/imports.py +5 -3
  22. datamodel_code_generator/model/pydantic_v2/root_model.py +6 -6
  23. datamodel_code_generator/model/pydantic_v2/types.py +11 -7
  24. datamodel_code_generator/model/rootmodel.py +1 -1
  25. datamodel_code_generator/model/scalar.py +33 -32
  26. datamodel_code_generator/model/typed_dict.py +41 -51
  27. datamodel_code_generator/model/types.py +24 -19
  28. datamodel_code_generator/model/union.py +21 -17
  29. datamodel_code_generator/parser/__init__.py +16 -12
  30. datamodel_code_generator/parser/base.py +327 -515
  31. datamodel_code_generator/parser/graphql.py +87 -119
  32. datamodel_code_generator/parser/jsonschema.py +438 -607
  33. datamodel_code_generator/parser/openapi.py +180 -220
  34. datamodel_code_generator/pydantic_patch.py +8 -9
  35. datamodel_code_generator/reference.py +199 -297
  36. datamodel_code_generator/types.py +149 -215
  37. datamodel_code_generator/util.py +23 -36
  38. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/METADATA +10 -5
  39. datamodel_code_generator-0.28.0.dist-info/RECORD +59 -0
  40. datamodel_code_generator-0.27.2.dist-info/RECORD +0 -59
  41. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/WHEEL +0 -0
  42. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/entry_points.txt +0 -0
  43. {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
- schema: Union[Dict[str, Any], List[Any]], keys: Union[List[str], List[int]]
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:]) # type: ignore
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
- f'Does not support json pointer to array. schema={schema}, key={keys}'
75
+ msg
96
76
  )
97
77
 
98
78
 
99
- json_schema_data_formats: Dict[str, Dict[str, Types]] = {
100
- 'integer': {
101
- 'int32': Types.int32,
102
- 'int64': Types.int64,
103
- 'default': Types.integer,
104
- 'date-time': Types.date_time,
105
- 'unix-time': Types.int64,
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
- 'number': {
108
- 'float': Types.float,
109
- 'double': Types.double,
110
- 'decimal': Types.decimal,
111
- 'date-time': Types.date_time,
112
- 'time': Types.time,
113
- 'default': Types.number,
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
- 'string': {
116
- 'default': Types.string,
117
- 'byte': Types.byte, # base64 encoded string
118
- 'binary': Types.binary,
119
- 'date': Types.date,
120
- 'date-time': Types.date_time,
121
- 'duration': Types.timedelta,
122
- 'time': Types.time,
123
- 'password': Types.password,
124
- 'path': Types.path,
125
- 'email': Types.email,
126
- 'idn-email': Types.email,
127
- 'uuid': Types.uuid,
128
- 'uuid1': Types.uuid1,
129
- 'uuid2': Types.uuid2,
130
- 'uuid3': Types.uuid3,
131
- 'uuid4': Types.uuid4,
132
- 'uuid5': Types.uuid5,
133
- 'uri': Types.uri,
134
- 'uri-reference': Types.string,
135
- 'hostname': Types.hostname,
136
- 'ipv4': Types.ipv4,
137
- 'ipv4-network': Types.ipv4_network,
138
- 'ipv6': Types.ipv6,
139
- 'ipv6-network': Types.ipv6_network,
140
- 'decimal': Types.decimal,
141
- 'integer': Types.integer,
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
- 'boolean': {'default': Types.boolean},
144
- 'object': {'default': Types.object},
145
- 'null': {'default': Types.null},
146
- 'array': {'default': Types.array},
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 = 'LOCAL'
152
- REMOTE = 'REMOTE'
153
- URL = '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[Dict[str, str]] = None
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) -> Dict[str, Any]:
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) -> Dict[str, Any]:
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__: Set[str] = {
180
- 'exclusiveMinimum',
181
- 'minimum',
182
- 'exclusiveMaximum',
183
- 'maximum',
184
- 'multipleOf',
185
- 'minItems',
186
- 'maxItems',
187
- 'minLength',
188
- 'maxLength',
189
- 'pattern',
190
- 'uniqueItems',
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('extras')
172
+ __extra_key__: str = SPECIAL_PATH_FORMAT.format("extras")
193
173
 
194
- @model_validator(mode='before')
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: Union[float, bool, None] = values.get('exclusiveMaximum')
199
- exclusive_minimum: Union[float, bool, None] = values.get('exclusiveMinimum')
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['exclusiveMaximum'] = values['maximum']
203
- del values['maximum']
182
+ values["exclusiveMaximum"] = values["maximum"]
183
+ del values["maximum"]
204
184
  elif exclusive_maximum is False:
205
- del values['exclusiveMaximum']
185
+ del values["exclusiveMaximum"]
206
186
  if exclusive_minimum is True:
207
- values['exclusiveMinimum'] = values['minimum']
208
- del values['minimum']
187
+ values["exclusiveMinimum"] = values["minimum"]
188
+ del values["minimum"]
209
189
  elif exclusive_minimum is False:
210
- del values['exclusiveMinimum']
190
+ del values["exclusiveMinimum"]
211
191
  return values
212
192
 
213
- @field_validator('ref')
214
- def validate_ref(cls, value: Any) -> Any:
215
- if isinstance(value, str) and '#' in value:
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
- elif '#/' in value or value[0] == '#' or value[-1] == '#':
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[List[JsonSchemaObject], JsonSchemaObject, bool, None] = None
224
- uniqueItems: Optional[bool] = None
225
- type: Union[str, List[str], None] = None
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, None] = None
236
- exclusiveMinimum: Union[float, bool, None] = None
237
- additionalProperties: Union[JsonSchemaObject, bool, None] = None
238
- patternProperties: Optional[Dict[str, JsonSchemaObject]] = None
239
- oneOf: List[JsonSchemaObject] = []
240
- anyOf: List[JsonSchemaObject] = []
241
- allOf: List[JsonSchemaObject] = []
242
- enum: List[Any] = []
243
- writeOnly: Optional[bool] = None
244
- readOnly: Optional[bool] = None
245
- properties: Optional[Dict[str, Union[JsonSchemaObject, bool]]] = None
246
- required: List[str] = []
247
- ref: Optional[str] = Field(default=None, alias='$ref')
248
- nullable: Optional[bool] = False
249
- x_enum_varnames: List[str] = Field(default=[], alias='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='$id')
256
- custom_type_path: Optional[str] = Field(default=None, alias='customTypePath')
257
- custom_base_path: Optional[str] = Field(default=None, alias='customBasePath')
258
- extras: Dict[str, Any] = Field(alias=__extra_key__, default_factory=dict)
259
- discriminator: Union[Discriminator, str, None] = None
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 [reportPossiblyUnboundVariable]
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 'const' in data.get(self.__extra_key__, {}):
278
- self.extras['const'] = data[self.__extra_key__]['const']
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.properties is not None
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 == 'array'
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('/', 1)[-1] # type: ignore
272
+ return (self.ref or "").rsplit("/", 1)[-1]
298
273
 
299
- @field_validator('items', mode='before')
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 'default' in self.__fields_set__ or 'default_factory' in self.extras
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) -> Optional[JSONReference]:
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 'null' in self.type
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
- elif is_url(ref):
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__: Optional[str] = None) -> Types:
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: Optional[Types] = json_schema_data_formats[type_].get(
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'format of {format__!r} not understood for {type_!r} - using default')
342
- return json_schema_data_formats[type_]['default']
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: Set[str] = {
348
- 'example',
349
- 'examples',
350
- 'description',
351
- 'discriminator',
352
- 'title',
353
- 'const',
354
- 'default_factory',
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: Set[str] = {
358
- 'readOnly',
359
- 'writeOnly',
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 [reportAttributeAccessIssue]
336
+ set(JsonSchemaObject.get_fields()) # pyright: ignore[reportAttributeAccessIssue]
364
337
  - DEFAULT_FIELD_KEYS
365
338
  - EXCLUDE_FIELD_KEYS_IN_JSON_SCHEMA
366
339
  ) | {
367
- '$id',
368
- '$ref',
340
+ "$id",
341
+ "$ref",
369
342
  JsonSchemaObject.__extra_key__,
370
343
  }
371
344
 
372
345
 
373
- @snooper_to_methods(max_variable_length=None)
346
+ @snooper_to_methods() # noqa: PLR0904
374
347
  class JsonSchemaParser(Parser):
375
- SCHEMA_PATHS: ClassVar[List[str]] = ['#/definitions', '#/$defs']
376
- SCHEMA_OBJECT_TYPE: ClassVar[Type[JsonSchemaObject]] = JsonSchemaObject
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: Union[str, Path, List[Path], ParseResult],
353
+ source: str | Path | list[Path] | ParseResult,
381
354
  *,
382
- data_model_type: Type[DataModel] = pydantic_model.BaseModel,
383
- data_model_root_type: Type[DataModel] = pydantic_model.CustomRootType,
384
- data_type_manager_type: Type[DataTypeManager] = pydantic_model.DataTypeManager,
385
- data_model_field_type: Type[DataModelFieldBase] = pydantic_model.DataModelField,
386
- base_class: Optional[str] = None,
387
- additional_imports: Optional[List[str]] = None,
388
- custom_template_dir: Optional[Path] = None,
389
- extra_template_data: Optional[DefaultDict[str, Dict[str, Any]]] = None,
390
- target_python_version: PythonVersion = PythonVersion.PY_38,
391
- dump_resolve_reference_action: Optional[Callable[[Iterable[str]], str]] = None,
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: Optional[Mapping[str, str]] = None,
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: Optional[str] = None,
374
+ class_name: str | None = None,
402
375
  use_standard_collections: bool = False,
403
- base_path: Optional[Path] = None,
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 = 'utf-8',
409
- enum_field_as_literal: Optional[LiteralType] = None,
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: Optional[DefaultPutDict[str, str]] = None,
389
+ remote_text_cache: DefaultPutDict[str, str] | None = None,
417
390
  disable_appending_item_suffix: bool = False,
418
- strict_types: Optional[Sequence[StrictTypes]] = None,
419
- empty_enum_field_name: Optional[str] = None,
420
- custom_class_name_generator: Optional[Callable[[str], str]] = None,
421
- field_extra_keys: Optional[Set[str]] = None,
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: Optional[Set[str]] = None,
424
- wrap_string_literal: Optional[bool] = None,
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: Optional[Sequence[Tuple[str, str]]] = None,
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: Optional[str] = None,
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: Optional[str] = None,
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: Optional[List[str]] = None,
442
- custom_formatters: Optional[List[str]] = None,
443
- custom_formatters_kwargs: Optional[Dict[str, Any]] = None,
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: Optional[Sequence[Tuple[str, str]]] = None,
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: Optional[Dict[str, Any]] = None,
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, Dict[str, Any]] = DefaultPutDict()
528
- self.raw_obj: Dict[Any, Any] = {}
529
- self._root_id: Optional[str] = None
530
- self._root_id_base_path: Optional[str] = None
531
- self.reserved_refs: DefaultDict[Tuple[str, ...], Set[str]] = defaultdict(set)
532
- self.field_keys: Set[str] = {
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) -> Dict[str, Any]:
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) -> List[Tuple[str, List[str]]]:
568
- return [(s, s.lstrip('#/').split('/')) for s in self.SCHEMA_PATHS]
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) -> Optional[str]:
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: Optional[str]) -> None:
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: Optional[str],
560
+ field_name: str | None,
600
561
  field: JsonSchemaObject,
601
562
  required: bool,
602
563
  field_type: DataType,
603
- alias: Optional[str],
604
- original_field_name: Optional[str],
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 'const' in obj.extras:
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
- _get_data_type(t, obj.format or 'default')
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 'default')
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]['additionalProperties'] = (
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]['title'] = obj.title
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
- elif isinstance(result[key], list) and isinstance(value, list):
677
- result[key] = result[key] + value
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: List[str],
635
+ path: list[str],
687
636
  target_attribute_name: str,
688
- ) -> List[DataType]:
689
- base_object = obj.dict(
690
- exclude={target_attribute_name}, exclude_unset=True, by_alias=True
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'{target_attribute_name}Common'
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, name: str, obj: JsonSchemaObject, path: List[str]
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, name: str, obj: JsonSchemaObject, path: List[str]
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: List[str],
762
- ignore_duplicate_model: bool,
763
- fields: List[DataModelFieldBase],
764
- base_classes: List[Reference],
765
- required: List[str],
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: List[str],
827
- fields: List[DataModelFieldBase],
828
- base_classes: List[Reference],
829
- required: List[str],
830
- union_models: List[Reference],
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
- else:
846
- if all_of_item.required:
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: List[str],
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 single_obj.ref and single_obj.ref_type == JSONReference.LOCAL:
882
- if get_model_by_path(self.raw_obj, single_obj.ref[2:].split('/')).get(
883
- 'enum'
884
- ):
885
- return self.get_ref_data_type(single_obj.ref)
886
- fields: List[DataModelFieldBase] = []
887
- base_classes: List[Reference] = []
888
- required: List[str] = []
889
- union_models: List[Reference] = []
890
- self._parse_all_of_item(
891
- name, obj, path, fields, base_classes, required, union_models
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('allOf', 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'union_model-{index}', path),
824
+ get_special_path(f"union_model-{index}", path),
913
825
  ignore_duplicate_model,
914
826
  [],
915
- [union_model, all_of_data_type.reference], # type: ignore
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, obj: JsonSchemaObject, path: List[str], module_name: Optional[str] = None
944
- ) -> List[DataModelFieldBase]:
945
- properties: Dict[str, Union[JsonSchemaObject, bool]] = (
946
- {} if obj.properties is None else obj.properties
947
- )
948
- requires: Set[str] = {*()} if obj.required is None else {*obj.required}
949
- fields: List[DataModelFieldBase] = []
950
-
951
- exclude_field_names: Set[str] = set()
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'{module_name}.{field_name}' if module_name else field_name
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: List[str],
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'{self.__class__.__name__}.parse_object() ignore `unique` argument.'
1010
- f'An object name must be unique.'
1011
- f'This argument will be removed in a future version'
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, 'additionalProperties'],
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: Dict[str, JsonSchemaObject],
1069
- path: List[str],
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'patternProperties/{i}', path),
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: List[str],
1096
- singular_name: bool = False,
1097
- parent: Optional[JsonSchemaObject] = None,
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
- parent
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
- elif item.ref:
1026
+ if item.ref:
1120
1027
  return self.get_ref_data_type(item.ref)
1121
- elif item.custom_type_path:
1122
- return self.data_type_manager.get_data_type_from_full_path(
1123
- item.custom_type_path, is_custom_type=True
1124
- )
1125
- elif item.is_array:
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
- elif item.anyOf:
1137
- return self.data_type(
1138
- data_types=self.parse_any_of(
1139
- name, item, get_special_path('anyOf', path)
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
- elif item.is_object or item.patternProperties:
1160
- object_path = get_special_path('object', 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
- name, item, object_path, singular_name=singular_name
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
- name, item.patternProperties, object_path
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
- elif item.enum:
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: List[JsonSchemaObject],
1192
- path: List[str],
1071
+ target_items: list[JsonSchemaObject],
1072
+ path: list[str],
1193
1073
  parent: JsonSchemaObject,
1194
- singular_name: bool = True,
1195
- ) -> List[DataType]:
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: List[str],
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: List[JsonSchemaObject] = [obj.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: List[DataType] = [
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: List[str],
1277
- original_name: Optional[str] = None,
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: List[str],
1194
+ path: list[str],
1327
1195
  ) -> DataType:
1328
- reference: Optional[Reference] = None
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('array', 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: List[DataType] = self.parse_any_of(
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: List[str],
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'{self.__class__.__name__}.parse_enum() ignore `unique` argument.'
1425
- f'An object name must be unique.'
1426
- f'This argument will be removed in a future version'
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: List[DataModelFieldBase] = []
1287
+ enum_fields: list[DataModelFieldBase] = []
1429
1288
 
1430
- if None in obj.enum and obj.type == 'string':
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: Set[str] = set()
1297
+ exclude_field_names: set[str] = set()
1439
1298
 
1440
1299
  for i, enum_part in enumerate(enum_times):
1441
- if obj.type == 'string' or isinstance(enum_part, str):
1442
- default = (
1443
- f"'{enum_part.translate(escape_characters)}'"
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
- obj.type
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='Enum',
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, 'Enum'],
1512
- f'{reference.name}Enum',
1357
+ [*path, "Enum"],
1358
+ f"{reference.name}Enum",
1513
1359
  class_name=True,
1514
1360
  singular_name=singular_name,
1515
- singular_name_suffix='Enum',
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) -> Dict[Any, Any]:
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) -> Dict[Any, Any]:
1551
- # URL Reference $ref: 'http://path/to/your/resource' Uses the whole document located on the different server.
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) -> Dict[Any, Any]:
1557
- # Remote Reference $ref: 'document.json' Uses the whole document located on the same server and in
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 $ref: '#/definitions/myElement'
1575
- self.reserved_refs[tuple(self.model_resolver.current_root)].add(ref) # type: ignore
1420
+ # Local Reference: $ref: '#/definitions/myElement'
1421
+ self.reserved_refs[tuple(self.model_resolver.current_root)].add(ref)
1576
1422
  return reference
1577
- elif self.model_resolver.is_after_load(ref):
1578
- self.reserved_refs[tuple(ref.split('#')[0].split('/'))].add(ref) # type: ignore
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 self.model_resolver.current_base_path_context(
1593
- base_path
1594
- ), self.model_resolver.base_url_context(relative_path):
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('/') if object_path else None,
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: List[str]) -> None:
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
- else:
1611
- if isinstance(obj.items, list):
1612
- for item in obj.items:
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: List[str]) -> None:
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
- else:
1637
- if isinstance(obj.items, list):
1638
- for item in obj.items:
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: Dict[str, Any]) -> Generator[None, None, None]:
1656
- root_id: Optional[str] = root_raw.get('$id')
1657
- previous_root_id: Optional[str] = self.root_id
1658
- self.root_id = root_id if root_id else None
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: Dict[str, Any],
1666
- path: List[str],
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: List[str],
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 == 'object':
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[Tuple[Source, List[str]]]:
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 self.model_resolver.current_base_path_context(
1714
- source.path.parent
1715
- ), self.model_resolver.current_root_context(path_parts):
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'{source.path} is empty. Skipping this file')
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('title', 'Model')
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('title', 'Model')
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)) # type: ignore
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 self.model_resolver.current_base_path_context(
1751
- source.path.parent
1752
- ), self.model_resolver.current_root_context(path_parts):
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
- self, raw: Dict[str, Any], ref: str, path_parts: List[str]
1766
- ) -> None:
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: Dict[str, Any],
1620
+ raw: dict[str, Any],
1781
1621
  obj_name: str,
1782
- path_parts: List[str],
1783
- object_paths: Optional[List[str]] = None,
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('self', None)
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: Optional[Dict[Any, Any]] = None
1801
- schema_path = ''
1802
- for schema_path, split_schema_path in self.schema_paths:
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, schema_path, key])
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, schema_path, key]
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('#/', 1)[-1].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: