jentic-openapi-datamodels 1.0.0a18__py3-none-any.whl → 1.0.0a19__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.
- jentic/apitools/openapi/datamodels/low/extractors.py +3 -3
- jentic/apitools/openapi/datamodels/low/v30/__init__.py +76 -0
- jentic/apitools/openapi/datamodels/low/v30/builders/__init__.py +312 -0
- jentic/apitools/openapi/datamodels/low/v30/callback.py +131 -0
- jentic/apitools/openapi/datamodels/low/v30/components.py +236 -0
- jentic/apitools/openapi/datamodels/low/v30/contact.py +4 -10
- jentic/apitools/openapi/datamodels/low/v30/discriminator.py +4 -9
- jentic/apitools/openapi/datamodels/low/v30/encoding.py +81 -0
- jentic/apitools/openapi/datamodels/low/v30/example.py +91 -0
- jentic/apitools/openapi/datamodels/low/v30/external_documentation.py +4 -10
- jentic/apitools/openapi/datamodels/low/v30/header.py +120 -0
- jentic/apitools/openapi/datamodels/low/v30/info.py +14 -23
- jentic/apitools/openapi/datamodels/low/v30/license.py +4 -10
- jentic/apitools/openapi/datamodels/low/v30/link.py +141 -0
- jentic/apitools/openapi/datamodels/low/v30/media_type.py +110 -0
- jentic/apitools/openapi/datamodels/low/v30/oauth_flow.py +4 -10
- jentic/apitools/openapi/datamodels/low/v30/oauth_flows.py +7 -15
- jentic/apitools/openapi/datamodels/low/v30/openapi.py +149 -0
- jentic/apitools/openapi/datamodels/low/v30/operation.py +134 -0
- jentic/apitools/openapi/datamodels/low/v30/parameter.py +123 -0
- jentic/apitools/openapi/datamodels/low/v30/path_item.py +125 -0
- jentic/apitools/openapi/datamodels/low/v30/paths.py +108 -0
- jentic/apitools/openapi/datamodels/low/v30/reference.py +5 -9
- jentic/apitools/openapi/datamodels/low/v30/request_body.py +108 -0
- jentic/apitools/openapi/datamodels/low/v30/response.py +104 -0
- jentic/apitools/openapi/datamodels/low/v30/responses.py +109 -0
- jentic/apitools/openapi/datamodels/low/v30/schema.py +81 -97
- jentic/apitools/openapi/datamodels/low/v30/security_requirement.py +14 -9
- jentic/apitools/openapi/datamodels/low/v30/security_scheme.py +42 -22
- jentic/apitools/openapi/datamodels/low/v30/server.py +111 -0
- jentic/apitools/openapi/datamodels/low/v30/server_variable.py +4 -10
- jentic/apitools/openapi/datamodels/low/v30/tag.py +8 -46
- jentic/apitools/openapi/datamodels/low/v30/xml.py +4 -10
- jentic/apitools/openapi/datamodels/low/v31/__init__.py +77 -0
- jentic/apitools/openapi/datamodels/low/v31/builders/__init__.py +347 -0
- jentic/apitools/openapi/datamodels/low/v31/callback.py +131 -0
- jentic/apitools/openapi/datamodels/low/v31/components.py +240 -0
- jentic/apitools/openapi/datamodels/low/v31/contact.py +61 -0
- jentic/apitools/openapi/datamodels/low/v31/discriminator.py +62 -0
- jentic/apitools/openapi/datamodels/low/v31/encoding.py +81 -0
- jentic/apitools/openapi/datamodels/low/v31/example.py +91 -0
- jentic/apitools/openapi/datamodels/low/v31/external_documentation.py +59 -0
- jentic/apitools/openapi/datamodels/low/v31/header.py +120 -0
- jentic/apitools/openapi/datamodels/low/v31/info.py +116 -0
- jentic/apitools/openapi/datamodels/low/v31/license.py +61 -0
- jentic/apitools/openapi/datamodels/low/v31/link.py +141 -0
- jentic/apitools/openapi/datamodels/low/v31/media_type.py +110 -0
- jentic/apitools/openapi/datamodels/low/v31/oauth_flow.py +65 -0
- jentic/apitools/openapi/datamodels/low/v31/oauth_flows.py +108 -0
- jentic/apitools/openapi/datamodels/low/v31/openapi.py +168 -0
- jentic/apitools/openapi/datamodels/low/v31/operation.py +133 -0
- jentic/apitools/openapi/datamodels/low/v31/parameter.py +123 -0
- jentic/apitools/openapi/datamodels/low/v31/path_item.py +125 -0
- jentic/apitools/openapi/datamodels/low/v31/paths.py +108 -0
- jentic/apitools/openapi/datamodels/low/v31/reference.py +65 -0
- jentic/apitools/openapi/datamodels/low/v31/request_body.py +108 -0
- jentic/apitools/openapi/datamodels/low/v31/response.py +104 -0
- jentic/apitools/openapi/datamodels/low/v31/responses.py +109 -0
- jentic/apitools/openapi/datamodels/low/v31/schema.py +498 -0
- jentic/apitools/openapi/datamodels/low/v31/security_requirement.py +106 -0
- jentic/apitools/openapi/datamodels/low/v31/security_scheme.py +129 -0
- jentic/apitools/openapi/datamodels/low/v31/server.py +111 -0
- jentic/apitools/openapi/datamodels/low/v31/server_variable.py +70 -0
- jentic/apitools/openapi/datamodels/low/v31/tag.py +63 -0
- jentic/apitools/openapi/datamodels/low/v31/xml.py +54 -0
- jentic_openapi_datamodels-1.0.0a19.dist-info/METADATA +372 -0
- jentic_openapi_datamodels-1.0.0a19.dist-info/RECORD +75 -0
- jentic/apitools/openapi/datamodels/low/model_builder.py +0 -129
- jentic_openapi_datamodels-1.0.0a18.dist-info/METADATA +0 -211
- jentic_openapi_datamodels-1.0.0a18.dist-info/RECORD +0 -27
- {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a19.dist-info}/WHEEL +0 -0
- {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a19.dist-info}/licenses/LICENSE +0 -0
- {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a19.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from ruamel import yaml
|
|
5
|
+
|
|
6
|
+
from ..context import Context
|
|
7
|
+
from ..fields import fixed_field
|
|
8
|
+
from ..sources import FieldSource, KeySource, ValueSource, YAMLInvalidValue, YAMLValue
|
|
9
|
+
from .builders import build_model
|
|
10
|
+
from .example import Example
|
|
11
|
+
from .reference import Reference
|
|
12
|
+
from .reference import build as build_reference
|
|
13
|
+
from .schema import BooleanJSONSchema, Schema
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from .media_type import MediaType
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__all__ = ["Header", "build", "build_header_or_reference"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True, slots=True)
|
|
24
|
+
class Header:
|
|
25
|
+
"""
|
|
26
|
+
Header Object representation for OpenAPI 3.1.
|
|
27
|
+
|
|
28
|
+
The Header Object follows the structure of the Parameter Object, including determining its
|
|
29
|
+
serialization strategy based on whether schema or content is present, with the following changes:
|
|
30
|
+
- name MUST NOT be specified, it is given in the corresponding headers map.
|
|
31
|
+
- in MUST NOT be specified, it is implicitly in header.
|
|
32
|
+
- All traits that are affected by the location MUST be applicable to a location of header
|
|
33
|
+
(for example, style). This means that allowEmptyValue and allowReserved MUST NOT be used,
|
|
34
|
+
and style, if used, MUST be limited to "simple".
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
root_node: The top-level node representing the entire Header object in the original source file
|
|
38
|
+
description: A brief description of the header. CommonMark syntax MAY be used for rich text representation.
|
|
39
|
+
required: Determines whether this header is mandatory. Default value is false.
|
|
40
|
+
deprecated: Specifies that a header is deprecated and SHOULD be transitioned out of usage. Default value is false.
|
|
41
|
+
style: Describes how the header value will be serialized depending on the type of the header value.
|
|
42
|
+
If used, MUST be limited to "simple".
|
|
43
|
+
explode: When this is true, header values of type array or object generate separate parameters for each value of the array or key-value pair of the map. Default value is false.
|
|
44
|
+
schema: The schema defining the type used for the header.
|
|
45
|
+
example: Example of the header's potential value. The example SHOULD match the specified schema and encoding properties if present.
|
|
46
|
+
examples: Examples of the header's potential value. Each example SHOULD contain a value in the correct format as specified in the header encoding.
|
|
47
|
+
content: A map containing the representations for the header. The key is the media type and the value describes it.
|
|
48
|
+
extensions: Specification extensions (x-* fields)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
root_node: yaml.Node
|
|
52
|
+
description: FieldSource[str] | None = fixed_field()
|
|
53
|
+
required: FieldSource[bool] | None = fixed_field()
|
|
54
|
+
deprecated: FieldSource[bool] | None = fixed_field()
|
|
55
|
+
style: FieldSource[str] | None = fixed_field()
|
|
56
|
+
explode: FieldSource[bool] | None = fixed_field()
|
|
57
|
+
schema: FieldSource["Schema | BooleanJSONSchema"] | None = fixed_field()
|
|
58
|
+
example: FieldSource[YAMLValue] | None = fixed_field()
|
|
59
|
+
examples: FieldSource[dict[KeySource[str], "Example | Reference"]] | None = fixed_field()
|
|
60
|
+
content: FieldSource[dict[KeySource[str], "MediaType"]] | None = fixed_field()
|
|
61
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def build(
|
|
65
|
+
root: yaml.Node, context: Context | None = None
|
|
66
|
+
) -> Header | ValueSource[YAMLInvalidValue]:
|
|
67
|
+
"""
|
|
68
|
+
Build a Header object from a YAML node.
|
|
69
|
+
|
|
70
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
71
|
+
model that provides complete source fidelity for inspection and validation.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
75
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
A Header object if the node is valid, or a ValueSource containing
|
|
79
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
80
|
+
and its source location for validation).
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
from ruamel.yaml import YAML
|
|
84
|
+
yaml = YAML()
|
|
85
|
+
root = yaml.compose('''
|
|
86
|
+
description: The number of allowed requests in the current period
|
|
87
|
+
schema:
|
|
88
|
+
type: integer
|
|
89
|
+
''')
|
|
90
|
+
header = build(root)
|
|
91
|
+
assert header.description.value == 'The number of allowed requests in the current period'
|
|
92
|
+
"""
|
|
93
|
+
return build_model(root, Header, context=context)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def build_header_or_reference(
|
|
97
|
+
node: yaml.Node, context: Context
|
|
98
|
+
) -> Header | Reference | ValueSource[YAMLInvalidValue]:
|
|
99
|
+
"""
|
|
100
|
+
Build either a Header or Reference from a YAML node.
|
|
101
|
+
|
|
102
|
+
This helper handles the polymorphic nature of OpenAPI where many fields
|
|
103
|
+
can contain either a Header object or a Reference object ($ref).
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
node: The YAML node to parse
|
|
107
|
+
context: Parsing context
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
A Header, Reference, or ValueSource if the node is invalid
|
|
111
|
+
"""
|
|
112
|
+
# Check if it's a reference (has $ref key)
|
|
113
|
+
if isinstance(node, yaml.MappingNode):
|
|
114
|
+
for key_node, _ in node.value:
|
|
115
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
116
|
+
if key == "$ref":
|
|
117
|
+
return build_reference(node, context)
|
|
118
|
+
|
|
119
|
+
# Otherwise, try to build as Header
|
|
120
|
+
return build(node, context)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from dataclasses import dataclass, field, replace
|
|
2
|
+
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
|
|
5
|
+
from ..context import Context
|
|
6
|
+
from ..fields import fixed_field
|
|
7
|
+
from ..sources import FieldSource, KeySource, ValueSource, YAMLInvalidValue, YAMLValue
|
|
8
|
+
from .builders import build_model
|
|
9
|
+
from .contact import Contact
|
|
10
|
+
from .contact import build as build_contact
|
|
11
|
+
from .license import License
|
|
12
|
+
from .license import build as build_license
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ["Info", "build"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True, slots=True)
|
|
19
|
+
class Info:
|
|
20
|
+
"""
|
|
21
|
+
Info Object representation for OpenAPI 3.1.
|
|
22
|
+
|
|
23
|
+
Provides metadata about the API. The metadata MAY be used by the clients if needed,
|
|
24
|
+
and MAY be presented in editing or documentation generation tools for convenience.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
root_node: The top-level node representing the entire Info object in the original source file
|
|
28
|
+
title: REQUIRED. The title of the API.
|
|
29
|
+
summary: A short summary of the API (new in OpenAPI 3.1).
|
|
30
|
+
description: A description of the API. CommonMark syntax MAY be used for rich text representation.
|
|
31
|
+
termsOfService: A URL to the Terms of Service for the API. This MUST be in the form of a URL.
|
|
32
|
+
contact: The contact information for the exposed API.
|
|
33
|
+
license: The license information for the exposed API.
|
|
34
|
+
version: REQUIRED. The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version).
|
|
35
|
+
extensions: Specification extensions (x-* fields)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
root_node: yaml.Node
|
|
39
|
+
title: FieldSource[str] | None = fixed_field()
|
|
40
|
+
summary: FieldSource[str] | None = fixed_field()
|
|
41
|
+
description: FieldSource[str] | None = fixed_field()
|
|
42
|
+
termsOfService: FieldSource[str] | None = fixed_field()
|
|
43
|
+
contact: FieldSource[Contact] | None = fixed_field()
|
|
44
|
+
license: FieldSource[License] | None = fixed_field()
|
|
45
|
+
version: FieldSource[str] | None = fixed_field()
|
|
46
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def build(root: yaml.Node, context: Context | None = None) -> Info | ValueSource[YAMLInvalidValue]:
|
|
50
|
+
"""
|
|
51
|
+
Build an Info object from a YAML node.
|
|
52
|
+
|
|
53
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
54
|
+
model that provides complete source fidelity for inspection and validation.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
58
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
An Info object if the node is valid, or a ValueSource containing
|
|
62
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
63
|
+
and its source location for validation).
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
from ruamel.yaml import YAML
|
|
67
|
+
yaml = YAML()
|
|
68
|
+
root = yaml.compose('''
|
|
69
|
+
title: Sample Pet Store App
|
|
70
|
+
version: 1.0.1
|
|
71
|
+
description: This is a sample server for a pet store.
|
|
72
|
+
contact:
|
|
73
|
+
name: API Support
|
|
74
|
+
email: support@example.com
|
|
75
|
+
license:
|
|
76
|
+
name: Apache 2.0
|
|
77
|
+
url: https://www.apache.org/licenses/LICENSE-2.0.html
|
|
78
|
+
''')
|
|
79
|
+
info = build(root)
|
|
80
|
+
assert info.title.value == 'Sample Pet Store App'
|
|
81
|
+
assert info.version.value == '1.0.1'
|
|
82
|
+
assert info.contact.value.name.value == 'API Support'
|
|
83
|
+
"""
|
|
84
|
+
context = context or Context()
|
|
85
|
+
|
|
86
|
+
# Use build_model for initial construction
|
|
87
|
+
info = build_model(root, Info, context=context)
|
|
88
|
+
|
|
89
|
+
# If build_model returned ValueSource (invalid node), return it immediately
|
|
90
|
+
if not isinstance(info, Info):
|
|
91
|
+
return info
|
|
92
|
+
|
|
93
|
+
# Manually handle nested objects (contact, license)
|
|
94
|
+
for key_node, value_node in root.value:
|
|
95
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
96
|
+
|
|
97
|
+
if key == "contact":
|
|
98
|
+
# Handle nested Contact object - child builder handles invalid nodes
|
|
99
|
+
# FieldSource will auto-unwrap ValueSource if child returns it for invalid data
|
|
100
|
+
contact = FieldSource(
|
|
101
|
+
value=build_contact(value_node, context=context),
|
|
102
|
+
key_node=key_node,
|
|
103
|
+
value_node=value_node,
|
|
104
|
+
)
|
|
105
|
+
info = replace(info, contact=contact)
|
|
106
|
+
elif key == "license":
|
|
107
|
+
# Handle nested License object - child builder handles invalid nodes
|
|
108
|
+
# FieldSource will auto-unwrap ValueSource if child returns it for invalid data
|
|
109
|
+
license_obj = FieldSource(
|
|
110
|
+
value=build_license(value_node, context=context),
|
|
111
|
+
key_node=key_node,
|
|
112
|
+
value_node=value_node,
|
|
113
|
+
)
|
|
114
|
+
info = replace(info, license=license_obj)
|
|
115
|
+
|
|
116
|
+
return info
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
|
|
5
|
+
from ..context import Context
|
|
6
|
+
from ..fields import fixed_field
|
|
7
|
+
from ..sources import FieldSource, KeySource, ValueSource, YAMLInvalidValue, YAMLValue
|
|
8
|
+
from .builders import build_model
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
__all__ = ["License", "build"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True, slots=True)
|
|
15
|
+
class License:
|
|
16
|
+
"""
|
|
17
|
+
License Object representation for OpenAPI 3.1.
|
|
18
|
+
|
|
19
|
+
License information for the exposed API.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
root_node: The top-level node representing the entire License object in the original source file
|
|
23
|
+
name: REQUIRED. The license name used for the API.
|
|
24
|
+
identifier: An SPDX license expression for the API. Mutually exclusive with the url field (new in OpenAPI 3.1).
|
|
25
|
+
url: A URL to the license used for the API. Value MUST be in the format of a URL. Mutually exclusive with the identifier field.
|
|
26
|
+
extensions: Specification extensions (x-* fields)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
root_node: yaml.Node
|
|
30
|
+
name: FieldSource[str] | None = fixed_field()
|
|
31
|
+
identifier: FieldSource[str] | None = fixed_field()
|
|
32
|
+
url: FieldSource[str] | None = fixed_field()
|
|
33
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build(
|
|
37
|
+
root: yaml.Node, context: Context | None = None
|
|
38
|
+
) -> License | ValueSource[YAMLInvalidValue]:
|
|
39
|
+
"""
|
|
40
|
+
Build a License object from a YAML node.
|
|
41
|
+
|
|
42
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
43
|
+
model that provides complete source fidelity for inspection and validation.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
47
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
A License object if the node is valid, or a ValueSource containing
|
|
51
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
52
|
+
and its source location for validation).
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
from ruamel.yaml import YAML
|
|
56
|
+
yaml = YAML()
|
|
57
|
+
root = yaml.compose("name: MIT\\nurl: https://opensource.org/licenses/MIT")
|
|
58
|
+
license = build(root)
|
|
59
|
+
assert license.name.value == 'MIT'
|
|
60
|
+
"""
|
|
61
|
+
return build_model(root, License, context=context)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from dataclasses import dataclass, field, replace
|
|
2
|
+
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
|
|
5
|
+
from ..context import Context
|
|
6
|
+
from ..fields import fixed_field
|
|
7
|
+
from ..sources import FieldSource, KeySource, ValueSource, YAMLInvalidValue, YAMLValue
|
|
8
|
+
from .builders import build_field_source, build_model
|
|
9
|
+
from .reference import Reference
|
|
10
|
+
from .reference import build as build_reference
|
|
11
|
+
from .server import Server
|
|
12
|
+
from .server import build as build_server
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ["Link", "build", "build_link_or_reference"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True, slots=True)
|
|
19
|
+
class Link:
|
|
20
|
+
"""
|
|
21
|
+
Link Object representation for OpenAPI 3.1.
|
|
22
|
+
|
|
23
|
+
The Link Object represents a possible design-time link for a response.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
root_node: The top-level node representing the entire Link object in the original source file
|
|
27
|
+
operation_ref: A relative or absolute URI reference to an OAS operation.
|
|
28
|
+
operation_id: The name of an existing, resolvable OAS operation.
|
|
29
|
+
parameters: A map representing parameters to pass to an operation as specified with operationId
|
|
30
|
+
or identified via operationRef.
|
|
31
|
+
request_body: A literal value or {expression} to use as a request body when calling the target operation.
|
|
32
|
+
description: A description of the link. CommonMark syntax MAY be used for rich text representation.
|
|
33
|
+
server: A server object to be used by the target operation.
|
|
34
|
+
extensions: Specification extensions (x-* fields)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
root_node: yaml.Node
|
|
38
|
+
operation_ref: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "operationRef"})
|
|
39
|
+
operation_id: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "operationId"})
|
|
40
|
+
parameters: FieldSource[dict[KeySource[str], ValueSource[YAMLValue]]] | None = fixed_field()
|
|
41
|
+
request_body: FieldSource[YAMLValue] | None = fixed_field(metadata={"yaml_name": "requestBody"})
|
|
42
|
+
description: FieldSource[str] | None = fixed_field()
|
|
43
|
+
server: FieldSource[Server] | None = fixed_field()
|
|
44
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def build(root: yaml.Node, context: Context | None = None) -> Link | ValueSource[YAMLInvalidValue]:
|
|
48
|
+
"""
|
|
49
|
+
Build a Link object from a YAML node.
|
|
50
|
+
|
|
51
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
52
|
+
model that provides complete source fidelity for inspection and validation.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
56
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
A Link object if the node is valid, or a ValueSource containing
|
|
60
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
61
|
+
and its source location for validation).
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
from ruamel.yaml import YAML
|
|
65
|
+
yaml = YAML()
|
|
66
|
+
root = yaml.compose("operationId: getUserById\\nparameters:\\n userId: $response.body#/id")
|
|
67
|
+
link = build(root)
|
|
68
|
+
assert link.operation_id.value == 'getUserById'
|
|
69
|
+
"""
|
|
70
|
+
context = context or Context()
|
|
71
|
+
|
|
72
|
+
# Use build_model for initial construction
|
|
73
|
+
link = build_model(root, Link, context=context)
|
|
74
|
+
|
|
75
|
+
# If build_model returned ValueSource (invalid node), return it immediately
|
|
76
|
+
if not isinstance(link, Link):
|
|
77
|
+
return link
|
|
78
|
+
|
|
79
|
+
# Manually handle nested server object and parameters dict
|
|
80
|
+
replacements = {}
|
|
81
|
+
for key_node, value_node in root.value:
|
|
82
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
83
|
+
|
|
84
|
+
if key == "server":
|
|
85
|
+
# Handle nested Server object - child builder handles invalid nodes
|
|
86
|
+
replacements["server"] = FieldSource(
|
|
87
|
+
value=build_server(value_node, context=context),
|
|
88
|
+
key_node=key_node,
|
|
89
|
+
value_node=value_node,
|
|
90
|
+
)
|
|
91
|
+
elif key == "parameters":
|
|
92
|
+
# Handle parameters map with KeySource/ValueSource wrapping
|
|
93
|
+
if isinstance(value_node, yaml.MappingNode):
|
|
94
|
+
params_dict: dict[KeySource[str], ValueSource[YAMLValue]] = {}
|
|
95
|
+
for param_key_node, param_value_node in value_node.value:
|
|
96
|
+
param_key = context.yaml_constructor.construct_yaml_str(param_key_node)
|
|
97
|
+
param_value = context.yaml_constructor.construct_object(
|
|
98
|
+
param_value_node, deep=True
|
|
99
|
+
)
|
|
100
|
+
params_dict[KeySource(value=param_key, key_node=param_key_node)] = ValueSource(
|
|
101
|
+
value=param_value, value_node=param_value_node
|
|
102
|
+
)
|
|
103
|
+
replacements["parameters"] = FieldSource(
|
|
104
|
+
value=params_dict, key_node=key_node, value_node=value_node
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
# Not a mapping - preserve as-is for validation
|
|
108
|
+
replacements["parameters"] = build_field_source(key_node, value_node, context)
|
|
109
|
+
|
|
110
|
+
# Apply all replacements at once
|
|
111
|
+
if replacements:
|
|
112
|
+
link = replace(link, **replacements)
|
|
113
|
+
|
|
114
|
+
return link
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def build_link_or_reference(
|
|
118
|
+
node: yaml.Node, context: Context
|
|
119
|
+
) -> Link | Reference | ValueSource[YAMLInvalidValue]:
|
|
120
|
+
"""
|
|
121
|
+
Build either a Link or Reference from a YAML node.
|
|
122
|
+
|
|
123
|
+
This helper handles the polymorphic nature of OpenAPI where many fields
|
|
124
|
+
can contain either a Link object or a Reference object ($ref).
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
node: The YAML node to parse
|
|
128
|
+
context: Parsing context
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
A Link, Reference, or ValueSource if the node is invalid
|
|
132
|
+
"""
|
|
133
|
+
# Check if it's a reference (has $ref key)
|
|
134
|
+
if isinstance(node, yaml.MappingNode):
|
|
135
|
+
for key_node, _ in node.value:
|
|
136
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
137
|
+
if key == "$ref":
|
|
138
|
+
return build_reference(node, context)
|
|
139
|
+
|
|
140
|
+
# Otherwise, try to build as Link
|
|
141
|
+
return build(node, context)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from dataclasses import dataclass, field, replace
|
|
2
|
+
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
|
|
5
|
+
from ..context import Context
|
|
6
|
+
from ..fields import fixed_field
|
|
7
|
+
from ..sources import FieldSource, KeySource, ValueSource, YAMLInvalidValue, YAMLValue
|
|
8
|
+
from .builders import build_field_source, build_model
|
|
9
|
+
from .encoding import Encoding
|
|
10
|
+
from .encoding import build as build_encoding
|
|
11
|
+
from .example import Example
|
|
12
|
+
from .reference import Reference
|
|
13
|
+
from .schema import BooleanJSONSchema, Schema
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = ["MediaType", "build"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True, slots=True)
|
|
20
|
+
class MediaType:
|
|
21
|
+
"""
|
|
22
|
+
Media Type Object representation for OpenAPI 3.1.
|
|
23
|
+
|
|
24
|
+
Each Media Type Object provides schema and examples for the media type identified by its key.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
root_node: The top-level node representing the entire Media Type object in the original source file
|
|
28
|
+
schema: The schema defining the content of the request, response, or parameter.
|
|
29
|
+
example: Example of the media type. The example SHOULD match the specified schema and encoding properties if present.
|
|
30
|
+
examples: Examples of the media type. Each example SHOULD contain a value in the correct format as specified in the parameter encoding.
|
|
31
|
+
encoding: A map between a property name and its encoding information. The key, being the property name,
|
|
32
|
+
MUST exist in the schema as a property. The encoding object SHALL only apply to requestBody objects
|
|
33
|
+
when the media type is multipart or application/x-www-form-urlencoded.
|
|
34
|
+
extensions: Specification extensions (x-* fields)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
root_node: yaml.Node
|
|
38
|
+
schema: FieldSource["Schema | BooleanJSONSchema"] | None = fixed_field()
|
|
39
|
+
example: FieldSource[YAMLValue] | None = fixed_field()
|
|
40
|
+
examples: FieldSource[dict[KeySource[str], "Example | Reference"]] | None = fixed_field()
|
|
41
|
+
encoding: FieldSource[dict[KeySource[str], Encoding]] | None = fixed_field()
|
|
42
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def build(
|
|
46
|
+
root: yaml.Node, context: Context | None = None
|
|
47
|
+
) -> MediaType | ValueSource[YAMLInvalidValue]:
|
|
48
|
+
"""
|
|
49
|
+
Build a MediaType object from a YAML node.
|
|
50
|
+
|
|
51
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
52
|
+
model that provides complete source fidelity for inspection and validation.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
56
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
A MediaType object if the node is valid, or a ValueSource containing
|
|
60
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
61
|
+
and its source location for validation).
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
from ruamel.yaml import YAML
|
|
65
|
+
yaml = YAML()
|
|
66
|
+
root = yaml.compose('''
|
|
67
|
+
schema:
|
|
68
|
+
type: string
|
|
69
|
+
examples:
|
|
70
|
+
user:
|
|
71
|
+
value: John Doe
|
|
72
|
+
''')
|
|
73
|
+
media_type = build(root)
|
|
74
|
+
assert media_type.schema.value.type.value == 'string'
|
|
75
|
+
"""
|
|
76
|
+
context = context or Context()
|
|
77
|
+
|
|
78
|
+
# Use build_model for initial construction
|
|
79
|
+
media_type = build_model(root, MediaType, context=context)
|
|
80
|
+
|
|
81
|
+
# If build_model returned ValueSource (invalid node), return it immediately
|
|
82
|
+
if not isinstance(media_type, MediaType):
|
|
83
|
+
return media_type
|
|
84
|
+
|
|
85
|
+
# Manually handle nested complex fields
|
|
86
|
+
for key_node, value_node in root.value:
|
|
87
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
88
|
+
|
|
89
|
+
if key == "encoding":
|
|
90
|
+
# Handle encoding field - map of Encoding objects
|
|
91
|
+
if isinstance(value_node, yaml.MappingNode):
|
|
92
|
+
encoding_dict: dict[KeySource[str], Encoding | ValueSource[YAMLInvalidValue]] = {}
|
|
93
|
+
for encoding_key_node, encoding_value_node in value_node.value:
|
|
94
|
+
encoding_key = context.yaml_constructor.construct_yaml_str(encoding_key_node)
|
|
95
|
+
# Build Encoding - child builder handles invalid nodes
|
|
96
|
+
encoding_obj = build_encoding(encoding_value_node, context)
|
|
97
|
+
encoding_dict[KeySource(value=encoding_key, key_node=encoding_key_node)] = (
|
|
98
|
+
encoding_obj
|
|
99
|
+
)
|
|
100
|
+
encoding = FieldSource(
|
|
101
|
+
value=encoding_dict, key_node=key_node, value_node=value_node
|
|
102
|
+
)
|
|
103
|
+
media_type = replace(media_type, encoding=encoding)
|
|
104
|
+
else:
|
|
105
|
+
# Not a mapping - preserve as-is for validation
|
|
106
|
+
encoding = build_field_source(key_node, value_node, context)
|
|
107
|
+
media_type = replace(media_type, encoding=encoding)
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
return media_type
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
|
|
5
|
+
from ..context import Context
|
|
6
|
+
from ..fields import fixed_field
|
|
7
|
+
from ..sources import FieldSource, KeySource, ValueSource, YAMLInvalidValue, YAMLValue
|
|
8
|
+
from .builders import build_model
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
__all__ = ["OAuthFlow", "build"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True, slots=True)
|
|
15
|
+
class OAuthFlow:
|
|
16
|
+
"""
|
|
17
|
+
OAuth Flow Object representation for OpenAPI 3.1.
|
|
18
|
+
|
|
19
|
+
Configuration details for a supported OAuth Flow.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
root_node: The top-level node representing the entire OAuth Flow object in the original source file
|
|
23
|
+
authorization_url: The authorization URL to be used for this flow. REQUIRED for implicit and authorization_code flows.
|
|
24
|
+
token_url: The token URL to be used for this flow. REQUIRED for password, client_credentials, and authorization_code flows.
|
|
25
|
+
refresh_url: The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL.
|
|
26
|
+
scopes: The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it.
|
|
27
|
+
extensions: Specification extensions (x-* fields)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
root_node: yaml.Node
|
|
31
|
+
authorization_url: FieldSource[str] | None = fixed_field(
|
|
32
|
+
metadata={"yaml_name": "authorizationUrl"}
|
|
33
|
+
)
|
|
34
|
+
token_url: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "tokenUrl"})
|
|
35
|
+
refresh_url: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "refreshUrl"})
|
|
36
|
+
scopes: FieldSource[dict[KeySource[str], ValueSource[str]]] | None = fixed_field()
|
|
37
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build(
|
|
41
|
+
root: yaml.Node, context: Context | None = None
|
|
42
|
+
) -> OAuthFlow | ValueSource[YAMLInvalidValue]:
|
|
43
|
+
"""
|
|
44
|
+
Build an OAuthFlow object from a YAML node.
|
|
45
|
+
|
|
46
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
47
|
+
model that provides complete source fidelity for inspection and validation.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
51
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
An OAuthFlow object if the node is valid, or a ValueSource containing
|
|
55
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
56
|
+
and its source location for validation).
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
from ruamel.yaml import YAML
|
|
60
|
+
yaml = YAML()
|
|
61
|
+
root = yaml.compose("tokenUrl: https://example.com/oauth/token\\nscopes:\\n read: Read access")
|
|
62
|
+
oauth_flow = build(root)
|
|
63
|
+
assert oauth_flow.tokenUrl.value == 'https://example.com/oauth/token'
|
|
64
|
+
"""
|
|
65
|
+
return build_model(root, OAuthFlow, context=context)
|