amati 0.3.14__py3-none-any.whl → 0.3.16__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.
- amati/_error_handler.py +33 -33
- amati/_references.py +226 -0
- amati/_resolve_forward_references.py +36 -60
- amati/amati.py +109 -16
- amati/exceptions.py +1 -1
- amati/fields/email.py +1 -1
- amati/fields/http_status_codes.py +2 -1
- amati/fields/iso9110.py +2 -1
- amati/fields/media.py +2 -1
- amati/fields/oas.py +1 -1
- amati/fields/spdx_licences.py +2 -1
- amati/fields/uri.py +2 -1
- amati/validators/_discriminators.py +8 -0
- amati/validators/generic.py +24 -16
- amati/validators/oas304.py +122 -50
- amati/validators/oas311.py +92 -37
- {amati-0.3.14.dist-info → amati-0.3.16.dist-info}/METADATA +1 -1
- {amati-0.3.14.dist-info → amati-0.3.16.dist-info}/RECORD +21 -19
- {amati-0.3.14.dist-info → amati-0.3.16.dist-info}/WHEEL +0 -0
- {amati-0.3.14.dist-info → amati-0.3.16.dist-info}/entry_points.txt +0 -0
- {amati-0.3.14.dist-info → amati-0.3.16.dist-info}/licenses/LICENSE +0 -0
amati/fields/media.py
CHANGED
|
@@ -8,7 +8,8 @@ from typing import cast
|
|
|
8
8
|
from abnf import ParseError
|
|
9
9
|
from abnf.grammars import rfc7231
|
|
10
10
|
|
|
11
|
-
from amati import
|
|
11
|
+
from amati import get
|
|
12
|
+
from amati.exceptions import AmatiValueError
|
|
12
13
|
from amati.fields import Str as _Str
|
|
13
14
|
|
|
14
15
|
reference_uri = "https://datatracker.ietf.org/doc/html/rfc7231#appendix-D"
|
amati/fields/oas.py
CHANGED
amati/fields/spdx_licences.py
CHANGED
amati/fields/uri.py
CHANGED
|
@@ -9,7 +9,8 @@ import idna
|
|
|
9
9
|
from abnf import Node, ParseError, Rule
|
|
10
10
|
from abnf.grammars import rfc3986, rfc3987
|
|
11
11
|
|
|
12
|
-
from amati import
|
|
12
|
+
from amati import get
|
|
13
|
+
from amati.exceptions import AmatiValueError
|
|
13
14
|
from amati.fields import Str as _Str
|
|
14
15
|
from amati.grammars import rfc6901
|
|
15
16
|
|
amati/validators/generic.py
CHANGED
|
@@ -13,13 +13,14 @@ from typing import (
|
|
|
13
13
|
cast,
|
|
14
14
|
)
|
|
15
15
|
|
|
16
|
-
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
|
16
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr, ValidationInfo, model_validator
|
|
17
17
|
from pydantic_core._pydantic_core import PydanticUndefined
|
|
18
18
|
|
|
19
19
|
from amati._logging import Logger
|
|
20
|
+
from amati._references import URICollectorMixin
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
class GenericObject(BaseModel):
|
|
23
|
+
class GenericObject(URICollectorMixin, BaseModel):
|
|
23
24
|
"""A generic model extending Pydantic BaseModel with enhanced validation.
|
|
24
25
|
|
|
25
26
|
Provides additional functionality for handling extra fields, including pattern
|
|
@@ -35,35 +36,41 @@ class GenericObject(BaseModel):
|
|
|
35
36
|
_reference_uri: ClassVar[str] = PrivateAttr()
|
|
36
37
|
_extra_field_pattern: re.Pattern[str] | None = PrivateAttr()
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Logs any fields that are not recognized as valid model fields or aliases
|
|
39
|
+
@model_validator(mode="before")
|
|
40
|
+
@classmethod
|
|
41
|
+
def _validate_extra_fields(cls, data: Any, info: ValidationInfo) -> Any:
|
|
42
|
+
"""Logs any fields that are not recognized as valid model fields or aliases
|
|
42
43
|
when extra fields are not allowed by the model configuration.
|
|
43
44
|
|
|
44
45
|
Args:
|
|
45
|
-
|
|
46
|
+
data: dict representing model data.
|
|
46
47
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if self.model_config.get("extra") == "allow":
|
|
50
|
-
return
|
|
48
|
+
if cls.model_config.get("extra") == "allow":
|
|
49
|
+
return data
|
|
51
50
|
|
|
52
51
|
# If extra fields aren't allowed log those that aren't going to be added
|
|
53
52
|
# to the model.
|
|
53
|
+
|
|
54
|
+
aliases = [field_info.alias for _, field_info in cls.model_fields.items()]
|
|
54
55
|
for field in data:
|
|
55
|
-
if field not in
|
|
56
|
-
message = f"{field} is not a valid field for {
|
|
56
|
+
if field not in cls.model_fields and field not in aliases:
|
|
57
|
+
message = f"{field} is not a valid field for {cls.__name__}."
|
|
57
58
|
Logger.log(
|
|
58
59
|
{
|
|
59
60
|
"msg": message,
|
|
60
61
|
"type": "value_error",
|
|
61
|
-
"loc": (
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
"loc": (
|
|
63
|
+
info.context.get("current_document")
|
|
64
|
+
if info.context
|
|
65
|
+
else cls.__name__,
|
|
66
|
+
),
|
|
67
|
+
"input": {field: data[field]},
|
|
68
|
+
"url": cls._reference_uri,
|
|
64
69
|
}
|
|
65
70
|
)
|
|
66
71
|
|
|
72
|
+
return data
|
|
73
|
+
|
|
67
74
|
def model_post_init(self, __context: Any) -> None:
|
|
68
75
|
"""Validate extra fields against the configured pattern after initialization.
|
|
69
76
|
|
|
@@ -148,6 +155,7 @@ def allow_extra_fields(pattern: str | None = None) -> Callable[[type[T]], type[T
|
|
|
148
155
|
"model_config": ConfigDict(extra="allow"),
|
|
149
156
|
"_extra_field_pattern": pattern,
|
|
150
157
|
}
|
|
158
|
+
|
|
151
159
|
# Create a new class with the updated configuration
|
|
152
160
|
return cast(type[T], type(cls.__name__, (cls,), namespace))
|
|
153
161
|
|
amati/validators/oas304.py
CHANGED
|
@@ -13,17 +13,21 @@ Note that per https://spec.openapis.org/oas/v3.0.4.html#relative-references-in-a
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
import re
|
|
16
|
-
from typing import Any, ClassVar, Self
|
|
16
|
+
from typing import Annotated, Any, ClassVar, Self
|
|
17
17
|
|
|
18
18
|
from jsonschema.exceptions import ValidationError as JSONVSchemeValidationError
|
|
19
19
|
from jsonschema.protocols import Validator as JSONSchemaValidator
|
|
20
20
|
from jsonschema.validators import validator_for # type: ignore
|
|
21
21
|
from pydantic import (
|
|
22
22
|
ConfigDict,
|
|
23
|
+
Discriminator,
|
|
23
24
|
Field,
|
|
24
25
|
RootModel,
|
|
26
|
+
SerializerFunctionWrapHandler,
|
|
27
|
+
Tag,
|
|
25
28
|
ValidationError,
|
|
26
29
|
field_validator,
|
|
30
|
+
model_serializer,
|
|
27
31
|
model_validator,
|
|
28
32
|
)
|
|
29
33
|
|
|
@@ -42,6 +46,7 @@ from amati.fields import (
|
|
|
42
46
|
from amati.fields.commonmark import CommonMark
|
|
43
47
|
from amati.fields.json import JSON
|
|
44
48
|
from amati.fields.oas import OpenAPI, RuntimeExpression
|
|
49
|
+
from amati.validators._discriminators import reference_object_disciminator
|
|
45
50
|
from amati.validators.generic import GenericObject, allow_extra_fields
|
|
46
51
|
|
|
47
52
|
type JSONPrimitive = str | int | float | bool | None
|
|
@@ -57,6 +62,58 @@ TITLE = "OpenAPI Specification v3.0.4"
|
|
|
57
62
|
specification_extensions = allow_extra_fields
|
|
58
63
|
|
|
59
64
|
|
|
65
|
+
CallbackReferenceType = Annotated[
|
|
66
|
+
Annotated["CallbackObject", Tag("other")]
|
|
67
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
68
|
+
Discriminator(reference_object_disciminator),
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
ExampleReferenceType = Annotated[
|
|
72
|
+
Annotated["ExampleObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
73
|
+
Discriminator(reference_object_disciminator),
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
HeaderReferenceType = Annotated[
|
|
77
|
+
Annotated["HeaderObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
78
|
+
Discriminator(reference_object_disciminator),
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
LinkReferenceType = Annotated[
|
|
82
|
+
Annotated["LinkObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
83
|
+
Discriminator(reference_object_disciminator),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
ParameterReferenceType = Annotated[
|
|
88
|
+
Annotated["ParameterObject", Tag("other")]
|
|
89
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
90
|
+
Discriminator(reference_object_disciminator),
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
ResponseReferenceType = Annotated[
|
|
94
|
+
Annotated["ResponseObject", Tag("other")]
|
|
95
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
96
|
+
Discriminator(reference_object_disciminator),
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
RequestBodyReferenceType = Annotated[
|
|
100
|
+
Annotated["RequestBodyObject", Tag("other")]
|
|
101
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
102
|
+
Discriminator(reference_object_disciminator),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
SchemaReferenceType = Annotated[
|
|
106
|
+
Annotated["SchemaObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
107
|
+
Discriminator(reference_object_disciminator),
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
SecuritySchemeReferenceType = Annotated[
|
|
111
|
+
Annotated["SecuritySchemeObject", Tag("other")]
|
|
112
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
113
|
+
Discriminator(reference_object_disciminator),
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
|
|
60
117
|
@specification_extensions("x-")
|
|
61
118
|
class ContactObject(GenericObject):
|
|
62
119
|
"""
|
|
@@ -150,6 +207,9 @@ class ExampleObject(GenericObject):
|
|
|
150
207
|
"https://spec.openapis.org/oas/v3.0.4.html#example-object"
|
|
151
208
|
)
|
|
152
209
|
|
|
210
|
+
# Note https://spec.openapis.org/oas/v3.1.1.html#example-object doesn't
|
|
211
|
+
# state that one of value and externalValue is required, however,
|
|
212
|
+
# there's very little point to an example object without either.
|
|
153
213
|
_not_value_and_external_value = mv.only_one_of(
|
|
154
214
|
["value", "externalValue"], "warning"
|
|
155
215
|
)
|
|
@@ -249,28 +309,6 @@ class PathsObject(GenericObject):
|
|
|
249
309
|
return data
|
|
250
310
|
|
|
251
311
|
|
|
252
|
-
@specification_extensions("x-")
|
|
253
|
-
class OperationObject(GenericObject):
|
|
254
|
-
"""Validates the OpenAPI Specification operation object - §4.8.10"""
|
|
255
|
-
|
|
256
|
-
tags: list[str] | None = None
|
|
257
|
-
summary: str | None = None
|
|
258
|
-
description: str | CommonMark | None = None
|
|
259
|
-
externalDocs: ExternalDocumentationObject | None = None
|
|
260
|
-
operationId: str | None = None
|
|
261
|
-
parameters: list[ParameterObject | ReferenceObject] | None = None
|
|
262
|
-
requestBody: RequestBodyObject | ReferenceObject | None = None
|
|
263
|
-
responses: ResponsesObject
|
|
264
|
-
callbacks: dict[str, CallbackObject | ReferenceObject] | None = None
|
|
265
|
-
deprecated: bool | None = False
|
|
266
|
-
security: list[SecurityRequirementObject] | None = None
|
|
267
|
-
servers: list[ServerObject] | None = None
|
|
268
|
-
|
|
269
|
-
_reference_uri: ClassVar[str] = (
|
|
270
|
-
"https://spec.openapis.org/oas/v3.0.4.html#operation-object"
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
|
|
274
312
|
PARAMETER_STYLES: set[str] = {
|
|
275
313
|
"matrix",
|
|
276
314
|
"label",
|
|
@@ -295,10 +333,10 @@ class ParameterObject(GenericObject):
|
|
|
295
333
|
style: str | None = None
|
|
296
334
|
explode: bool | None = None
|
|
297
335
|
allowReserved: bool | None = None
|
|
298
|
-
schema_:
|
|
336
|
+
schema_: SchemaReferenceType | None = Field(alias="schema")
|
|
299
337
|
example: Any | None = None
|
|
300
|
-
examples: dict[str,
|
|
301
|
-
content: dict[str, MediaTypeObject] | None = None
|
|
338
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
339
|
+
content: dict[str, "MediaTypeObject"] | None = None # noqa: UP037
|
|
302
340
|
_reference_uri: ClassVar[str] = (
|
|
303
341
|
"https://spec.openapis.org/oas/v3.0.4.html#parameter-object"
|
|
304
342
|
)
|
|
@@ -356,10 +394,10 @@ class MediaTypeObject(GenericObject):
|
|
|
356
394
|
Validates the OpenAPI Specification media type object - §4.8.14
|
|
357
395
|
"""
|
|
358
396
|
|
|
359
|
-
schema_:
|
|
397
|
+
schema_: SchemaReferenceType | None = Field(alias="schema", default=None)
|
|
360
398
|
# FIXME: Define example
|
|
361
399
|
example: Any | None = None
|
|
362
|
-
examples: dict[str,
|
|
400
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
363
401
|
encoding: EncodingObject | None = None
|
|
364
402
|
_reference_uri: ClassVar[str] = (
|
|
365
403
|
"https://spec.openapis.org/oas/v3.0.4.html#media-type-object"
|
|
@@ -373,7 +411,7 @@ class EncodingObject(GenericObject):
|
|
|
373
411
|
"""
|
|
374
412
|
|
|
375
413
|
contentType: str | None = None
|
|
376
|
-
headers: dict[str,
|
|
414
|
+
headers: dict[str, HeaderReferenceType] | None = None
|
|
377
415
|
_reference_uri: ClassVar[str] = (
|
|
378
416
|
"https://spec.openapis.org/oas/v3.0.4.html#encoding object-object"
|
|
379
417
|
)
|
|
@@ -394,7 +432,7 @@ class EncodingObject(GenericObject):
|
|
|
394
432
|
return value
|
|
395
433
|
|
|
396
434
|
|
|
397
|
-
type _ResponsesObjectReturnType = dict[str,
|
|
435
|
+
type _ResponsesObjectReturnType = dict[str, ResponseReferenceType]
|
|
398
436
|
|
|
399
437
|
|
|
400
438
|
@specification_extensions(".*")
|
|
@@ -407,7 +445,7 @@ class ResponsesObject(GenericObject):
|
|
|
407
445
|
extra="allow",
|
|
408
446
|
)
|
|
409
447
|
|
|
410
|
-
default:
|
|
448
|
+
default: ResponseReferenceType | None = None
|
|
411
449
|
_reference_uri: ClassVar[str] = (
|
|
412
450
|
"https://spec.openapis.org/oas/v3.0.4.html#responses-object"
|
|
413
451
|
)
|
|
@@ -484,9 +522,9 @@ class ResponseObject(GenericObject):
|
|
|
484
522
|
"""
|
|
485
523
|
|
|
486
524
|
description: str | CommonMark
|
|
487
|
-
headers: dict[str,
|
|
525
|
+
headers: dict[str, HeaderReferenceType] | None = None
|
|
488
526
|
content: dict[str, MediaTypeObject] | None = None
|
|
489
|
-
links: dict[str,
|
|
527
|
+
links: dict[str, LinkReferenceType] | None = None
|
|
490
528
|
_reference_uri: ClassVar[str] = (
|
|
491
529
|
"https://spec.openapis.org/oas/v3.0.4.html#response-object"
|
|
492
530
|
)
|
|
@@ -603,9 +641,9 @@ class HeaderObject(GenericObject):
|
|
|
603
641
|
# Schema fields
|
|
604
642
|
style: str | None = Field(default="simple")
|
|
605
643
|
explode: bool | None = Field(default=False)
|
|
606
|
-
schema_:
|
|
644
|
+
schema_: SchemaReferenceType | None = Field(alias="schema", default=None)
|
|
607
645
|
example: JSONValue | None = None
|
|
608
|
-
examples: dict[str,
|
|
646
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
609
647
|
|
|
610
648
|
# Content fields
|
|
611
649
|
content: dict[str, MediaTypeObject] | None = None
|
|
@@ -781,6 +819,20 @@ class OAuthFlowObject(GenericObject):
|
|
|
781
819
|
conditions={"type": "password"}, consequences={"tokenUrl": mv.UNKNOWN}
|
|
782
820
|
)
|
|
783
821
|
|
|
822
|
+
@model_serializer(mode="wrap", when_used="json")
|
|
823
|
+
def serialize_model(
|
|
824
|
+
self, handler: SerializerFunctionWrapHandler
|
|
825
|
+
) -> dict[str, object]:
|
|
826
|
+
"""
|
|
827
|
+
Serializes the type field for JSON output only.
|
|
828
|
+
The Python output is used inside model_validators, so
|
|
829
|
+
a standard Field(exclude=True) cannot be used.
|
|
830
|
+
"""
|
|
831
|
+
|
|
832
|
+
serialized = handler(self)
|
|
833
|
+
serialized.pop("type", None)
|
|
834
|
+
return serialized
|
|
835
|
+
|
|
784
836
|
|
|
785
837
|
@specification_extensions("-x")
|
|
786
838
|
class OAuthFlowsObject(GenericObject):
|
|
@@ -803,16 +855,14 @@ class OAuthFlowsObject(GenericObject):
|
|
|
803
855
|
@classmethod
|
|
804
856
|
def _push_down_type(cls, data: Any) -> Any:
|
|
805
857
|
"""
|
|
806
|
-
Adds the type of OAuth2 flow, e.g. implicit, password to the child
|
|
858
|
+
Adds the type of OAuth2 flow, e.g. implicit, password, to the child
|
|
807
859
|
OAuthFlowObject so that additional validation can be done on this object.
|
|
808
860
|
"""
|
|
809
861
|
|
|
810
|
-
for
|
|
811
|
-
if isinstance(
|
|
862
|
+
for field, value in data.items():
|
|
863
|
+
if isinstance(value, OAuthFlowObject):
|
|
812
864
|
raise NotImplementedError("Must pass a dict")
|
|
813
|
-
|
|
814
|
-
if v:
|
|
815
|
-
data[k]["type"] = k
|
|
865
|
+
data[field]["type"] = field
|
|
816
866
|
|
|
817
867
|
return data
|
|
818
868
|
|
|
@@ -888,6 +938,28 @@ class SecurityRequirementObject(RootModel[list[_Requirement] | _Requirement]):
|
|
|
888
938
|
)
|
|
889
939
|
|
|
890
940
|
|
|
941
|
+
@specification_extensions("x-")
|
|
942
|
+
class OperationObject(GenericObject):
|
|
943
|
+
"""Validates the OpenAPI Specification operation object - §4.8.10"""
|
|
944
|
+
|
|
945
|
+
tags: list[str] | None = None
|
|
946
|
+
summary: str | None = None
|
|
947
|
+
description: str | CommonMark | None = None
|
|
948
|
+
externalDocs: ExternalDocumentationObject | None = None
|
|
949
|
+
operationId: str | None = None
|
|
950
|
+
parameters: list[ParameterReferenceType] | None = None
|
|
951
|
+
requestBody: RequestBodyReferenceType | None = None
|
|
952
|
+
responses: ResponsesObject
|
|
953
|
+
callbacks: dict[str, CallbackReferenceType] | None = None
|
|
954
|
+
deprecated: bool | None = False
|
|
955
|
+
security: list[SecurityRequirementObject] | None = None
|
|
956
|
+
servers: list[ServerObject] | None = None
|
|
957
|
+
|
|
958
|
+
_reference_uri: ClassVar[str] = (
|
|
959
|
+
"https://spec.openapis.org/oas/v3.0.4.html#operation-object"
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
|
|
891
963
|
@specification_extensions("x-")
|
|
892
964
|
class PathItemObject(GenericObject):
|
|
893
965
|
"""Validates the OpenAPI Specification path item object - §4.8.9"""
|
|
@@ -904,7 +976,7 @@ class PathItemObject(GenericObject):
|
|
|
904
976
|
patch: OperationObject | None = None
|
|
905
977
|
trace: OperationObject | None = None
|
|
906
978
|
servers: list[ServerObject] | None = None
|
|
907
|
-
parameters: list[
|
|
979
|
+
parameters: list[ParameterReferenceType] | None = None
|
|
908
980
|
_reference_uri: ClassVar[str] = (
|
|
909
981
|
"https://spec.openapis.org/oas/v3.0.4.html#path-item-object"
|
|
910
982
|
)
|
|
@@ -917,14 +989,14 @@ class ComponentsObject(GenericObject):
|
|
|
917
989
|
"""
|
|
918
990
|
|
|
919
991
|
schemas: dict[str, SchemaObject] | None = None
|
|
920
|
-
responses: dict[str,
|
|
921
|
-
parameters: dict[str,
|
|
922
|
-
examples: dict[str,
|
|
923
|
-
requestBodies: dict[str,
|
|
924
|
-
headers: dict[str,
|
|
925
|
-
securitySchemes: dict[str,
|
|
926
|
-
links: dict[str,
|
|
927
|
-
callbacks: dict[str,
|
|
992
|
+
responses: dict[str, ResponseReferenceType] | None = None
|
|
993
|
+
parameters: dict[str, ParameterReferenceType] | None = None
|
|
994
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
995
|
+
requestBodies: dict[str, RequestBodyReferenceType] | None = None
|
|
996
|
+
headers: dict[str, HeaderReferenceType] | None = None
|
|
997
|
+
securitySchemes: dict[str, SecuritySchemeReferenceType] | None = None
|
|
998
|
+
links: dict[str, LinkReferenceType] | None = None
|
|
999
|
+
callbacks: dict[str, CallbackReferenceType] | None = None
|
|
928
1000
|
_reference_uri: ClassVar[str] = (
|
|
929
1001
|
"https://spec.openapis.org/oas/v3.0.4.html#components-object"
|
|
930
1002
|
)
|
amati/validators/oas311.py
CHANGED
|
@@ -13,15 +13,17 @@ Note that per https://spec.openapis.org/oas/v3.1.1.html#relative-references-in-a
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
import re
|
|
16
|
-
from typing import Any, ClassVar, Self
|
|
16
|
+
from typing import Annotated, Any, ClassVar, Self
|
|
17
17
|
|
|
18
18
|
from jsonschema.exceptions import ValidationError as JSONVSchemeValidationError
|
|
19
19
|
from jsonschema.protocols import Validator as JSONSchemaValidator
|
|
20
20
|
from jsonschema.validators import validator_for # type: ignore
|
|
21
21
|
from pydantic import (
|
|
22
22
|
ConfigDict,
|
|
23
|
+
Discriminator,
|
|
23
24
|
Field,
|
|
24
25
|
RootModel,
|
|
26
|
+
Tag,
|
|
25
27
|
model_validator,
|
|
26
28
|
)
|
|
27
29
|
|
|
@@ -37,6 +39,7 @@ from amati.fields.commonmark import CommonMark
|
|
|
37
39
|
from amati.fields.json import JSON
|
|
38
40
|
from amati.fields.oas import OpenAPI
|
|
39
41
|
from amati.fields.spdx_licences import VALID_LICENCES
|
|
42
|
+
from amati.validators._discriminators import reference_object_disciminator
|
|
40
43
|
from amati.validators.generic import GenericObject, allow_extra_fields
|
|
41
44
|
from amati.validators.oas304 import (
|
|
42
45
|
CallbackObject,
|
|
@@ -64,6 +67,58 @@ TITLE = "OpenAPI Specification v3.1.1"
|
|
|
64
67
|
specification_extensions = allow_extra_fields
|
|
65
68
|
|
|
66
69
|
|
|
70
|
+
CallbackReferenceType = Annotated[
|
|
71
|
+
Annotated["CallbackObject", Tag("other")]
|
|
72
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
73
|
+
Discriminator(reference_object_disciminator),
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
ExampleReferenceType = Annotated[
|
|
77
|
+
Annotated["ExampleObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
78
|
+
Discriminator(reference_object_disciminator),
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
HeaderReferenceType = Annotated[
|
|
82
|
+
Annotated["HeaderObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
83
|
+
Discriminator(reference_object_disciminator),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
LinkReferenceType = Annotated[
|
|
87
|
+
Annotated["LinkObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
88
|
+
Discriminator(reference_object_disciminator),
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
ParameterReferenceType = Annotated[
|
|
93
|
+
Annotated["ParameterObject", Tag("other")]
|
|
94
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
95
|
+
Discriminator(reference_object_disciminator),
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
ResponseReferenceType = Annotated[
|
|
99
|
+
Annotated["ResponseObject", Tag("other")]
|
|
100
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
101
|
+
Discriminator(reference_object_disciminator),
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
RequestBodyReferenceType = Annotated[
|
|
105
|
+
Annotated["RequestBodyObject", Tag("other")]
|
|
106
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
107
|
+
Discriminator(reference_object_disciminator),
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
SchemaReferenceType = Annotated[
|
|
111
|
+
Annotated["SchemaObject", Tag("other")] | Annotated["ReferenceObject", Tag("ref")],
|
|
112
|
+
Discriminator(reference_object_disciminator),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
SecuritySchemeReferenceType = Annotated[
|
|
116
|
+
Annotated["SecuritySchemeObject", Tag("other")]
|
|
117
|
+
| Annotated["ReferenceObject", Tag("ref")],
|
|
118
|
+
Discriminator(reference_object_disciminator),
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
|
|
67
122
|
@specification_extensions("x-")
|
|
68
123
|
class LicenceObject(GenericObject):
|
|
69
124
|
"""
|
|
@@ -226,28 +281,6 @@ class ServerVariableObject(GenericObject):
|
|
|
226
281
|
return self
|
|
227
282
|
|
|
228
283
|
|
|
229
|
-
@specification_extensions("x-")
|
|
230
|
-
class OperationObject(GenericObject):
|
|
231
|
-
"""Validates the OpenAPI Specification operation object - §4.8.10"""
|
|
232
|
-
|
|
233
|
-
tags: list[str] | None = None
|
|
234
|
-
summary: str | None = None
|
|
235
|
-
description: str | CommonMark | None = None
|
|
236
|
-
externalDocs: ExternalDocumentationObject | None = None
|
|
237
|
-
operationId: str | None = None
|
|
238
|
-
parameters: list[ParameterObject | ReferenceObject] | None = None
|
|
239
|
-
requestBody: RequestBodyObject | ReferenceObject | None = None
|
|
240
|
-
responses: ResponsesObject | None = None
|
|
241
|
-
callbacks: dict[str, CallbackObject | ReferenceObject] | None = None
|
|
242
|
-
deprecated: bool | None = False
|
|
243
|
-
security: list[SecurityRequirementObject] | None = None
|
|
244
|
-
servers: list[ServerObject] | None = None
|
|
245
|
-
|
|
246
|
-
_reference_uri: ClassVar[str] = (
|
|
247
|
-
"https://spec.openapis.org/oas/v3.1.1.html#operation-object"
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
|
|
251
284
|
PARAMETER_STYLES: set[str] = {
|
|
252
285
|
"matrix",
|
|
253
286
|
"label",
|
|
@@ -272,10 +305,10 @@ class ParameterObject(GenericObject):
|
|
|
272
305
|
style: str | None = None
|
|
273
306
|
explode: bool | None = None
|
|
274
307
|
allowReserved: bool | None = None
|
|
275
|
-
schema_: SchemaObject | None = Field(alias="schema")
|
|
308
|
+
schema_: "SchemaObject | None" = Field(alias="schema") # noqa: UP037
|
|
276
309
|
example: Any | None = None
|
|
277
|
-
examples: dict[str,
|
|
278
|
-
content: dict[str, MediaTypeObject] | None = None
|
|
310
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
311
|
+
content: dict[str, "MediaTypeObject"] | None = None # noqa: UP037
|
|
279
312
|
_reference_uri: ClassVar[str] = (
|
|
280
313
|
"https://spec.openapis.org/oas/v3.1.1.html#parameter-object"
|
|
281
314
|
)
|
|
@@ -319,10 +352,10 @@ class MediaTypeObject(GenericObject):
|
|
|
319
352
|
Validates the OpenAPI Specification media type object - §4.8.14
|
|
320
353
|
"""
|
|
321
354
|
|
|
322
|
-
schema_: SchemaObject | None = Field(alias="schema", default=None)
|
|
355
|
+
schema_: "SchemaObject | None" = Field(alias="schema", default=None) # noqa: UP037
|
|
323
356
|
# FIXME: Define example
|
|
324
357
|
example: Any | None = None
|
|
325
|
-
examples: dict[str,
|
|
358
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
326
359
|
encoding: EncodingObject | None = None
|
|
327
360
|
_reference_uri: ClassVar[str] = (
|
|
328
361
|
"https://spec.openapis.org/oas/v3.1.1.html#media-type-object"
|
|
@@ -437,21 +470,43 @@ class SecurityRequirementObject(RootModel[list[_Requirement] | _Requirement]):
|
|
|
437
470
|
)
|
|
438
471
|
|
|
439
472
|
|
|
473
|
+
@specification_extensions("x-")
|
|
474
|
+
class OperationObject(GenericObject):
|
|
475
|
+
"""Validates the OpenAPI Specification operation object - §4.8.10"""
|
|
476
|
+
|
|
477
|
+
tags: list[str] | None = None
|
|
478
|
+
summary: str | None = None
|
|
479
|
+
description: str | CommonMark | None = None
|
|
480
|
+
externalDocs: ExternalDocumentationObject | None = None
|
|
481
|
+
operationId: str | None = None
|
|
482
|
+
parameters: list[ParameterReferenceType] | None = None
|
|
483
|
+
requestBody: RequestBodyReferenceType | None = None
|
|
484
|
+
responses: ResponsesObject | None = None
|
|
485
|
+
callbacks: dict[str, CallbackReferenceType] | None = None
|
|
486
|
+
deprecated: bool | None = False
|
|
487
|
+
security: list[SecurityRequirementObject] | None = None
|
|
488
|
+
servers: list[ServerObject] | None = None
|
|
489
|
+
|
|
490
|
+
_reference_uri: ClassVar[str] = (
|
|
491
|
+
"https://spec.openapis.org/oas/v3.1.1.html#operation-object"
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
|
|
440
495
|
@specification_extensions("x-")
|
|
441
496
|
class ComponentsObject(GenericObject):
|
|
442
497
|
"""
|
|
443
498
|
Validates the OpenAPI Specification components object - §4.8.7
|
|
444
499
|
"""
|
|
445
500
|
|
|
446
|
-
schemas: dict[str,
|
|
447
|
-
responses: dict[str,
|
|
448
|
-
parameters: dict[str,
|
|
449
|
-
examples: dict[str,
|
|
450
|
-
requestBodies: dict[str,
|
|
451
|
-
headers: dict[str,
|
|
452
|
-
securitySchemes: dict[str,
|
|
453
|
-
links: dict[str,
|
|
454
|
-
callbacks: dict[str,
|
|
501
|
+
schemas: dict[str, SchemaReferenceType] | None = None
|
|
502
|
+
responses: dict[str, ResponseReferenceType] | None = None
|
|
503
|
+
parameters: dict[str, ParameterReferenceType] | None = None
|
|
504
|
+
examples: dict[str, ExampleReferenceType] | None = None
|
|
505
|
+
requestBodies: dict[str, RequestBodyReferenceType] | None = None
|
|
506
|
+
headers: dict[str, HeaderReferenceType] | None = None
|
|
507
|
+
securitySchemes: dict[str, SecuritySchemeReferenceType] | None = None
|
|
508
|
+
links: dict[str, LinkReferenceType] | None = None
|
|
509
|
+
callbacks: dict[str, CallbackReferenceType] | None = None
|
|
455
510
|
pathItems: dict[str, PathItemObject] | None = None
|
|
456
511
|
_reference_uri: ClassVar[str] = (
|
|
457
512
|
"https://spec.openapis.org/oas/v3.1.1.html#components-object"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amati
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.16
|
|
4
4
|
Summary: Validates that a .yaml or .json file conforms to the OpenAPI Specifications 3.x.
|
|
5
5
|
Project-URL: Homepage, https://github.com/gwyli/amati
|
|
6
6
|
Project-URL: Issues, https://github.com/gwyli/amati/issues
|