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.
Files changed (73) hide show
  1. jentic/apitools/openapi/datamodels/low/extractors.py +3 -3
  2. jentic/apitools/openapi/datamodels/low/v30/__init__.py +76 -0
  3. jentic/apitools/openapi/datamodels/low/v30/builders/__init__.py +312 -0
  4. jentic/apitools/openapi/datamodels/low/v30/callback.py +131 -0
  5. jentic/apitools/openapi/datamodels/low/v30/components.py +236 -0
  6. jentic/apitools/openapi/datamodels/low/v30/contact.py +4 -10
  7. jentic/apitools/openapi/datamodels/low/v30/discriminator.py +4 -9
  8. jentic/apitools/openapi/datamodels/low/v30/encoding.py +81 -0
  9. jentic/apitools/openapi/datamodels/low/v30/example.py +91 -0
  10. jentic/apitools/openapi/datamodels/low/v30/external_documentation.py +4 -10
  11. jentic/apitools/openapi/datamodels/low/v30/header.py +120 -0
  12. jentic/apitools/openapi/datamodels/low/v30/info.py +14 -23
  13. jentic/apitools/openapi/datamodels/low/v30/license.py +4 -10
  14. jentic/apitools/openapi/datamodels/low/v30/link.py +141 -0
  15. jentic/apitools/openapi/datamodels/low/v30/media_type.py +110 -0
  16. jentic/apitools/openapi/datamodels/low/v30/oauth_flow.py +4 -10
  17. jentic/apitools/openapi/datamodels/low/v30/oauth_flows.py +7 -15
  18. jentic/apitools/openapi/datamodels/low/v30/openapi.py +149 -0
  19. jentic/apitools/openapi/datamodels/low/v30/operation.py +134 -0
  20. jentic/apitools/openapi/datamodels/low/v30/parameter.py +123 -0
  21. jentic/apitools/openapi/datamodels/low/v30/path_item.py +125 -0
  22. jentic/apitools/openapi/datamodels/low/v30/paths.py +108 -0
  23. jentic/apitools/openapi/datamodels/low/v30/reference.py +5 -9
  24. jentic/apitools/openapi/datamodels/low/v30/request_body.py +108 -0
  25. jentic/apitools/openapi/datamodels/low/v30/response.py +104 -0
  26. jentic/apitools/openapi/datamodels/low/v30/responses.py +109 -0
  27. jentic/apitools/openapi/datamodels/low/v30/schema.py +81 -97
  28. jentic/apitools/openapi/datamodels/low/v30/security_requirement.py +14 -9
  29. jentic/apitools/openapi/datamodels/low/v30/security_scheme.py +42 -22
  30. jentic/apitools/openapi/datamodels/low/v30/server.py +111 -0
  31. jentic/apitools/openapi/datamodels/low/v30/server_variable.py +4 -10
  32. jentic/apitools/openapi/datamodels/low/v30/tag.py +8 -46
  33. jentic/apitools/openapi/datamodels/low/v30/xml.py +4 -10
  34. jentic/apitools/openapi/datamodels/low/v31/__init__.py +77 -0
  35. jentic/apitools/openapi/datamodels/low/v31/builders/__init__.py +347 -0
  36. jentic/apitools/openapi/datamodels/low/v31/callback.py +131 -0
  37. jentic/apitools/openapi/datamodels/low/v31/components.py +240 -0
  38. jentic/apitools/openapi/datamodels/low/v31/contact.py +61 -0
  39. jentic/apitools/openapi/datamodels/low/v31/discriminator.py +62 -0
  40. jentic/apitools/openapi/datamodels/low/v31/encoding.py +81 -0
  41. jentic/apitools/openapi/datamodels/low/v31/example.py +91 -0
  42. jentic/apitools/openapi/datamodels/low/v31/external_documentation.py +59 -0
  43. jentic/apitools/openapi/datamodels/low/v31/header.py +120 -0
  44. jentic/apitools/openapi/datamodels/low/v31/info.py +116 -0
  45. jentic/apitools/openapi/datamodels/low/v31/license.py +61 -0
  46. jentic/apitools/openapi/datamodels/low/v31/link.py +141 -0
  47. jentic/apitools/openapi/datamodels/low/v31/media_type.py +110 -0
  48. jentic/apitools/openapi/datamodels/low/v31/oauth_flow.py +65 -0
  49. jentic/apitools/openapi/datamodels/low/v31/oauth_flows.py +108 -0
  50. jentic/apitools/openapi/datamodels/low/v31/openapi.py +168 -0
  51. jentic/apitools/openapi/datamodels/low/v31/operation.py +133 -0
  52. jentic/apitools/openapi/datamodels/low/v31/parameter.py +123 -0
  53. jentic/apitools/openapi/datamodels/low/v31/path_item.py +125 -0
  54. jentic/apitools/openapi/datamodels/low/v31/paths.py +108 -0
  55. jentic/apitools/openapi/datamodels/low/v31/reference.py +65 -0
  56. jentic/apitools/openapi/datamodels/low/v31/request_body.py +108 -0
  57. jentic/apitools/openapi/datamodels/low/v31/response.py +104 -0
  58. jentic/apitools/openapi/datamodels/low/v31/responses.py +109 -0
  59. jentic/apitools/openapi/datamodels/low/v31/schema.py +498 -0
  60. jentic/apitools/openapi/datamodels/low/v31/security_requirement.py +106 -0
  61. jentic/apitools/openapi/datamodels/low/v31/security_scheme.py +129 -0
  62. jentic/apitools/openapi/datamodels/low/v31/server.py +111 -0
  63. jentic/apitools/openapi/datamodels/low/v31/server_variable.py +70 -0
  64. jentic/apitools/openapi/datamodels/low/v31/tag.py +63 -0
  65. jentic/apitools/openapi/datamodels/low/v31/xml.py +54 -0
  66. jentic_openapi_datamodels-1.0.0a19.dist-info/METADATA +372 -0
  67. jentic_openapi_datamodels-1.0.0a19.dist-info/RECORD +75 -0
  68. jentic/apitools/openapi/datamodels/low/model_builder.py +0 -129
  69. jentic_openapi_datamodels-1.0.0a18.dist-info/METADATA +0 -211
  70. jentic_openapi_datamodels-1.0.0a18.dist-info/RECORD +0 -27
  71. {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a19.dist-info}/WHEEL +0 -0
  72. {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a19.dist-info}/licenses/LICENSE +0 -0
  73. {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a19.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,240 @@
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 .callback import Callback
10
+ from .example import Example, build_example_or_reference
11
+ from .header import Header
12
+ from .link import Link
13
+ from .parameter import Parameter, build_parameter_or_reference
14
+ from .path_item import PathItem
15
+ from .reference import Reference
16
+ from .request_body import RequestBody, build_request_body_or_reference
17
+ from .response import Response, build_response_or_reference
18
+ from .schema import BooleanJSONSchema, Schema
19
+ from .schema import build as build_schema
20
+ from .security_scheme import SecurityScheme, build_security_scheme_or_reference
21
+
22
+
23
+ __all__ = ["Components", "build"]
24
+
25
+
26
+ @dataclass(frozen=True, slots=True)
27
+ class Components:
28
+ r"""
29
+ Components Object representation for OpenAPI 3.1.
30
+
31
+ Holds reusable objects for different aspects of the OAS. All objects defined within
32
+ the components object have no effect on the API unless they are explicitly referenced
33
+ from properties outside the components object.
34
+
35
+ All component keys MUST match the regex pattern: ^[a-zA-Z0-9\.\-_]+$
36
+ (Note: This is a validation concern and not enforced by this low-level model)
37
+
38
+ Attributes:
39
+ root_node: The top-level node representing the entire Components object in the original source file
40
+ schemas: Reusable Schema Objects (can include $ref directly in OpenAPI 3.1)
41
+ responses: Reusable Response Objects or Reference Objects
42
+ parameters: Reusable Parameter Objects or Reference Objects
43
+ examples: Reusable Example Objects or Reference Objects
44
+ request_bodies: Reusable Request Body Objects or Reference Objects
45
+ headers: Reusable Header Objects or Reference Objects
46
+ security_schemes: Reusable Security Scheme Objects or Reference Objects
47
+ links: Reusable Link Objects or Reference Objects
48
+ callbacks: Reusable Callback Objects or Reference Objects
49
+ path_items: Reusable Path Item Objects (new in OpenAPI 3.1)
50
+ extensions: Specification extensions (x-* fields)
51
+ """
52
+
53
+ root_node: yaml.Node
54
+ schemas: FieldSource[dict[KeySource[str], Schema | BooleanJSONSchema]] | None = fixed_field()
55
+ responses: FieldSource[dict[KeySource[str], Response | Reference]] | None = fixed_field()
56
+ parameters: FieldSource[dict[KeySource[str], Parameter | Reference]] | None = fixed_field()
57
+ examples: FieldSource[dict[KeySource[str], Example | Reference]] | None = fixed_field()
58
+ request_bodies: FieldSource[dict[KeySource[str], RequestBody | Reference]] | None = fixed_field(
59
+ metadata={"yaml_name": "requestBodies"}
60
+ )
61
+ headers: FieldSource[dict[KeySource[str], "Header | Reference"]] | None = fixed_field()
62
+ security_schemes: FieldSource[dict[KeySource[str], SecurityScheme | Reference]] | None = (
63
+ fixed_field(metadata={"yaml_name": "securitySchemes"})
64
+ )
65
+ links: FieldSource[dict[KeySource[str], "Link | Reference"]] | None = fixed_field()
66
+ callbacks: FieldSource[dict[KeySource[str], "Callback | Reference"]] | None = fixed_field()
67
+ path_items: FieldSource[dict[KeySource[str], "PathItem"]] | None = fixed_field(
68
+ metadata={"yaml_name": "pathItems"}
69
+ )
70
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
71
+
72
+
73
+ def build(
74
+ root: yaml.Node, context: Context | None = None
75
+ ) -> Components | ValueSource[YAMLInvalidValue]:
76
+ """
77
+ Build a Components object from a YAML node.
78
+
79
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
80
+ model that provides complete source fidelity for inspection and validation.
81
+
82
+ Args:
83
+ root: The YAML node to parse (should be a MappingNode)
84
+ context: Optional parsing context. If None, a default context will be created.
85
+
86
+ Returns:
87
+ A Components object if the node is valid, or a ValueSource containing
88
+ the invalid data if the root is not a MappingNode (preserving the invalid data
89
+ and its source location for validation).
90
+
91
+ Example:
92
+ from ruamel.yaml import YAML
93
+ yaml = YAML()
94
+ root = yaml.compose('''
95
+ schemas:
96
+ User:
97
+ type: object
98
+ properties:
99
+ id:
100
+ type: integer
101
+ name:
102
+ type: string
103
+ responses:
104
+ NotFound:
105
+ description: Entity not found
106
+ ''')
107
+ components = build(root)
108
+ assert 'User' in {k.value for k in components.schemas.value.keys()}
109
+ """
110
+ context = context or Context()
111
+
112
+ # Use build_model for initial construction
113
+ components_obj = build_model(root, Components, context=context)
114
+
115
+ # If build_model returned ValueSource (invalid node), return it immediately
116
+ if not isinstance(components_obj, Components):
117
+ return components_obj
118
+
119
+ # Manually handle nested complex fields that aren't covered by build_model
120
+ replacements = {}
121
+ for key_node, value_node in root.value:
122
+ key = context.yaml_constructor.construct_yaml_str(key_node)
123
+
124
+ if key == "schemas":
125
+ # Handle schemas field - map of Schema objects (in 3.1, schemas can have $ref directly)
126
+ if isinstance(value_node, yaml.MappingNode):
127
+ schemas_dict = {}
128
+ for schema_key_node, schema_value_node in value_node.value:
129
+ schema_key = context.yaml_constructor.construct_yaml_str(schema_key_node)
130
+ schema = build_schema(schema_value_node, context)
131
+ schemas_dict[KeySource(value=schema_key, key_node=schema_key_node)] = schema
132
+ replacements["schemas"] = FieldSource(
133
+ value=schemas_dict, key_node=key_node, value_node=value_node
134
+ )
135
+ else:
136
+ # Not a mapping - preserve as-is for validation
137
+ replacements["schemas"] = build_field_source(key_node, value_node, context)
138
+
139
+ elif key == "responses":
140
+ # Handle responses field - map of Response or Reference objects
141
+ if isinstance(value_node, yaml.MappingNode):
142
+ responses_dict = {}
143
+ for response_key_node, response_value_node in value_node.value:
144
+ response_key = context.yaml_constructor.construct_yaml_str(response_key_node)
145
+ response_or_reference = build_response_or_reference(
146
+ response_value_node, context
147
+ )
148
+ responses_dict[KeySource(value=response_key, key_node=response_key_node)] = (
149
+ response_or_reference
150
+ )
151
+ replacements["responses"] = FieldSource(
152
+ value=responses_dict, key_node=key_node, value_node=value_node
153
+ )
154
+ else:
155
+ # Not a mapping - preserve as-is for validation
156
+ replacements["responses"] = build_field_source(key_node, value_node, context)
157
+
158
+ elif key == "parameters":
159
+ # Handle parameters field - map of Parameter or Reference objects
160
+ if isinstance(value_node, yaml.MappingNode):
161
+ parameters_dict = {}
162
+ for parameter_key_node, parameter_value_node in value_node.value:
163
+ parameter_key = context.yaml_constructor.construct_yaml_str(parameter_key_node)
164
+ parameter_or_reference = build_parameter_or_reference(
165
+ parameter_value_node, context
166
+ )
167
+ parameters_dict[KeySource(value=parameter_key, key_node=parameter_key_node)] = (
168
+ parameter_or_reference
169
+ )
170
+ replacements["parameters"] = FieldSource(
171
+ value=parameters_dict, key_node=key_node, value_node=value_node
172
+ )
173
+ else:
174
+ # Not a mapping - preserve as-is for validation
175
+ replacements["parameters"] = build_field_source(key_node, value_node, context)
176
+
177
+ elif key == "examples":
178
+ # Handle examples field - map of Example or Reference objects
179
+ if isinstance(value_node, yaml.MappingNode):
180
+ examples_dict = {}
181
+ for example_key_node, example_value_node in value_node.value:
182
+ example_key = context.yaml_constructor.construct_yaml_str(example_key_node)
183
+ example_or_reference = build_example_or_reference(example_value_node, context)
184
+ examples_dict[KeySource(value=example_key, key_node=example_key_node)] = (
185
+ example_or_reference
186
+ )
187
+ replacements["examples"] = FieldSource(
188
+ value=examples_dict, key_node=key_node, value_node=value_node
189
+ )
190
+ else:
191
+ # Not a mapping - preserve as-is for validation
192
+ replacements["examples"] = build_field_source(key_node, value_node, context)
193
+
194
+ elif key == "requestBodies":
195
+ # Handle requestBodies field - map of RequestBody or Reference objects
196
+ if isinstance(value_node, yaml.MappingNode):
197
+ request_bodies_dict = {}
198
+ for request_body_key_node, request_body_value_node in value_node.value:
199
+ request_body_key = context.yaml_constructor.construct_yaml_str(
200
+ request_body_key_node
201
+ )
202
+ request_body_or_reference = build_request_body_or_reference(
203
+ request_body_value_node, context
204
+ )
205
+ request_bodies_dict[
206
+ KeySource(value=request_body_key, key_node=request_body_key_node)
207
+ ] = request_body_or_reference
208
+ replacements["request_bodies"] = FieldSource(
209
+ value=request_bodies_dict, key_node=key_node, value_node=value_node
210
+ )
211
+ else:
212
+ # Not a mapping - preserve as-is for validation
213
+ replacements["request_bodies"] = build_field_source(key_node, value_node, context)
214
+
215
+ elif key == "securitySchemes":
216
+ # Handle securitySchemes field - map of SecurityScheme or Reference objects
217
+ if isinstance(value_node, yaml.MappingNode):
218
+ security_schemes_dict = {}
219
+ for security_scheme_key_node, security_scheme_value_node in value_node.value:
220
+ security_scheme_key = context.yaml_constructor.construct_yaml_str(
221
+ security_scheme_key_node
222
+ )
223
+ security_scheme_or_reference = build_security_scheme_or_reference(
224
+ security_scheme_value_node, context
225
+ )
226
+ security_schemes_dict[
227
+ KeySource(value=security_scheme_key, key_node=security_scheme_key_node)
228
+ ] = security_scheme_or_reference
229
+ replacements["security_schemes"] = FieldSource(
230
+ value=security_schemes_dict, key_node=key_node, value_node=value_node
231
+ )
232
+ else:
233
+ # Not a mapping - preserve as-is for validation
234
+ replacements["security_schemes"] = build_field_source(key_node, value_node, context)
235
+
236
+ # Apply all replacements at once
237
+ if replacements:
238
+ components_obj = replace(components_obj, **replacements)
239
+
240
+ return components_obj
@@ -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__ = ["Contact", "build"]
12
+
13
+
14
+ @dataclass(frozen=True, slots=True)
15
+ class Contact:
16
+ """
17
+ Contact Object representation for OpenAPI 3.1.
18
+
19
+ Contact information for the exposed API.
20
+
21
+ Attributes:
22
+ root_node: The top-level node representing the entire Contact object in the original source file
23
+ name: The identifying name of the contact person/organization.
24
+ url: The URL pointing to the contact information. Value MUST be in the format of a URL.
25
+ email: The email address of the contact person/organization. Value MUST be in the format of an email address.
26
+ extensions: Specification extensions (x-* fields)
27
+ """
28
+
29
+ root_node: yaml.Node
30
+ name: FieldSource[str] | None = fixed_field()
31
+ url: FieldSource[str] | None = fixed_field()
32
+ email: 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
+ ) -> Contact | ValueSource[YAMLInvalidValue]:
39
+ """
40
+ Build a Contact 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 Contact 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: API Support\\nemail: support@example.com")
58
+ contact = build(root)
59
+ assert contact.name.value == 'API Support'
60
+ """
61
+ return build_model(root, Contact, context=context)
@@ -0,0 +1,62 @@
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__ = ["Discriminator", "build"]
12
+
13
+
14
+ @dataclass(frozen=True, slots=True)
15
+ class Discriminator:
16
+ """
17
+ Discriminator Object representation for OpenAPI 3.1.
18
+
19
+ When request bodies or response payloads may be one of a number of different schemas,
20
+ a discriminator object can be used to aid in serialization, deserialization, and validation.
21
+
22
+ In OpenAPI 3.1, the Discriminator Object supports Specification Extensions (x-* fields).
23
+
24
+ Attributes:
25
+ root_node: The top-level node representing the entire Discriminator object in the original source file
26
+ property_name: REQUIRED. The name of the property in the payload that will hold the discriminator value
27
+ mapping: An optional mapping of discriminator values to schema names or references
28
+ extensions: Specification extensions (x-* fields)
29
+ """
30
+
31
+ root_node: yaml.Node
32
+ property_name: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "propertyName"})
33
+ mapping: FieldSource[dict[KeySource[str], ValueSource[str]]] | None = fixed_field()
34
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
35
+
36
+
37
+ def build(
38
+ root: yaml.Node, context: Context | None = None
39
+ ) -> Discriminator | ValueSource[YAMLInvalidValue]:
40
+ """
41
+ Build a Discriminator object from a YAML node.
42
+
43
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
44
+ model that provides complete source fidelity for inspection and validation.
45
+
46
+ Args:
47
+ root: The YAML node to parse (should be a MappingNode)
48
+ context: Optional parsing context. If None, a default context will be created.
49
+
50
+ Returns:
51
+ A Discriminator object if the node is valid, or a ValueSource containing
52
+ the invalid data if the root is not a MappingNode (preserving the invalid data
53
+ and its source location for validation).
54
+
55
+ Example:
56
+ from ruamel.yaml import YAML
57
+ yaml = YAML()
58
+ root = yaml.compose("propertyName: petType\\nmapping:\\n dog: Dog\\n cat: Cat")
59
+ discriminator = build(root)
60
+ assert discriminator.property_name.value == 'petType'
61
+ """
62
+ return build_model(root, Discriminator, context=context)
@@ -0,0 +1,81 @@
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
+ from .header import Header
10
+ from .reference import Reference
11
+
12
+
13
+ __all__ = ["Encoding", "build"]
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class Encoding:
18
+ """
19
+ Encoding Object representation for OpenAPI 3.1.
20
+
21
+ A single encoding definition applied to a single schema property.
22
+
23
+ Attributes:
24
+ root_node: The top-level node representing the entire Encoding object in the original source file
25
+ contentType: The Content-Type for encoding a specific property. Default value depends on the property type:
26
+ for string with format being binary – application/octet-stream;
27
+ for other primitive types – text/plain;
28
+ for object - application/json;
29
+ for array – the default is defined based on the inner type.
30
+ headers: A map allowing additional information to be provided as headers. Content-Type is described
31
+ separately and SHALL be ignored if included.
32
+ style: Describes how a specific property value will be serialized depending on its type.
33
+ explode: When this is true, property values of type array or object generate separate parameters
34
+ for each value of the array, or key-value-pair of the map. For other data types this property
35
+ has no effect. Default value is true.
36
+ allowReserved: Determines whether the parameter value SHOULD allow reserved characters, as defined by
37
+ RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding. The default value is false.
38
+ extensions: Specification extensions (x-* fields)
39
+ """
40
+
41
+ root_node: yaml.Node
42
+ contentType: FieldSource[str] | None = fixed_field()
43
+ headers: FieldSource[dict[KeySource[str], "Header | Reference"]] | None = fixed_field()
44
+ style: FieldSource[str] | None = fixed_field()
45
+ explode: FieldSource[bool] | None = fixed_field()
46
+ allowReserved: FieldSource[bool] | None = fixed_field()
47
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
48
+
49
+
50
+ def build(
51
+ root: yaml.Node, context: Context | None = None
52
+ ) -> Encoding | ValueSource[YAMLInvalidValue]:
53
+ """
54
+ Build an Encoding object from a YAML node.
55
+
56
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
57
+ model that provides complete source fidelity for inspection and validation.
58
+
59
+ Args:
60
+ root: The YAML node to parse (should be a MappingNode)
61
+ context: Optional parsing context. If None, a default context will be created.
62
+
63
+ Returns:
64
+ An Encoding object if the node is valid, or a ValueSource containing
65
+ the invalid data if the root is not a MappingNode (preserving the invalid data
66
+ and its source location for validation).
67
+
68
+ Example:
69
+ from ruamel.yaml import YAML
70
+ yaml = YAML()
71
+ root = yaml.compose('''
72
+ contentType: application/xml
73
+ headers:
74
+ X-Rate-Limit:
75
+ schema:
76
+ type: integer
77
+ ''')
78
+ encoding = build(root)
79
+ assert encoding.contentType.value == 'application/xml'
80
+ """
81
+ return build_model(root, Encoding, context=context)
@@ -0,0 +1,91 @@
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
+ from .reference import Reference
10
+ from .reference import build as build_reference
11
+
12
+
13
+ __all__ = ["Example", "build", "build_example_or_reference"]
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class Example:
18
+ """
19
+ Example Object representation for OpenAPI 3.1.
20
+
21
+ Attributes:
22
+ root_node: The top-level node representing the entire Example object in the original source file
23
+ summary: A short description of the example.
24
+ description: A long description for the example. CommonMark syntax MAY be used for rich text representation.
25
+ value: Embedded literal example. The value field and externalValue field are mutually exclusive.
26
+ external_value: A URL that points to the literal example. This provides the capability to reference
27
+ examples that cannot be inlined. The value field and externalValue field are mutually exclusive.
28
+ extensions: Specification extensions (x-* fields)
29
+ """
30
+
31
+ root_node: yaml.Node
32
+ summary: FieldSource[str] | None = fixed_field()
33
+ description: FieldSource[str] | None = fixed_field()
34
+ value: FieldSource[YAMLValue] | None = fixed_field()
35
+ external_value: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "externalValue"})
36
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
37
+
38
+
39
+ def build(
40
+ root: yaml.Node, context: Context | None = None
41
+ ) -> Example | ValueSource[YAMLInvalidValue]:
42
+ """
43
+ Build an Example object from a YAML node.
44
+
45
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
46
+ model that provides complete source fidelity for inspection and validation.
47
+
48
+ Args:
49
+ root: The YAML node to parse (should be a MappingNode)
50
+ context: Optional parsing context. If None, a default context will be created.
51
+
52
+ Returns:
53
+ An Example object if the node is valid, or a ValueSource containing
54
+ the invalid data if the root is not a MappingNode (preserving the invalid data
55
+ and its source location for validation).
56
+
57
+ Example:
58
+ from ruamel.yaml import YAML
59
+ yaml = YAML()
60
+ root = yaml.compose("summary: A user example\\nvalue:\\n id: 1\\n name: John")
61
+ example = build(root)
62
+ assert example.summary.value == 'A user example'
63
+ """
64
+ return build_model(root, Example, context=context)
65
+
66
+
67
+ def build_example_or_reference(
68
+ node: yaml.Node, context: Context
69
+ ) -> Example | Reference | ValueSource[YAMLInvalidValue]:
70
+ """
71
+ Build either an Example or Reference from a YAML node.
72
+
73
+ This helper handles the polymorphic nature of OpenAPI where many fields
74
+ can contain either an Example object or a Reference object ($ref).
75
+
76
+ Args:
77
+ node: The YAML node to parse
78
+ context: Parsing context
79
+
80
+ Returns:
81
+ An Example, Reference, or ValueSource if the node is invalid
82
+ """
83
+ # Check if it's a reference (has $ref key)
84
+ if isinstance(node, yaml.MappingNode):
85
+ for key_node, _ in node.value:
86
+ key = context.yaml_constructor.construct_yaml_str(key_node)
87
+ if key == "$ref":
88
+ return build_reference(node, context)
89
+
90
+ # Otherwise, try to build as Example
91
+ return build(node, context)
@@ -0,0 +1,59 @@
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__ = ["ExternalDocumentation", "build"]
12
+
13
+
14
+ @dataclass(frozen=True, slots=True)
15
+ class ExternalDocumentation:
16
+ """
17
+ External Documentation Object representation for OpenAPI 3.1.
18
+
19
+ Allows referencing an external resource for extended documentation.
20
+
21
+ Attributes:
22
+ root_node: The top-level node representing the entire External Documentation object in the original source file
23
+ description: A short description of the target documentation. CommonMark syntax MAY be used for rich text representation.
24
+ url: The URL for the target documentation. REQUIRED. Value MUST be in the format of a URL.
25
+ extensions: Specification extensions (x-* fields)
26
+ """
27
+
28
+ root_node: yaml.Node
29
+ description: FieldSource[str] | None = fixed_field()
30
+ url: FieldSource[str] | None = fixed_field()
31
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
32
+
33
+
34
+ def build(
35
+ root: yaml.Node, context: Context | None = None
36
+ ) -> ExternalDocumentation | ValueSource[YAMLInvalidValue]:
37
+ """
38
+ Build an ExternalDocumentation object from a YAML node.
39
+
40
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
41
+ model that provides complete source fidelity for inspection and validation.
42
+
43
+ Args:
44
+ root: The YAML node to parse (should be a MappingNode)
45
+ context: Optional parsing context. If None, a default context will be created.
46
+
47
+ Returns:
48
+ An ExternalDocumentation object if the node is valid, or a ValueSource containing
49
+ the invalid data if the root is not a MappingNode (preserving the invalid data
50
+ and its source location for validation).
51
+
52
+ Example:
53
+ from ruamel.yaml import YAML
54
+ yaml = YAML()
55
+ root = yaml.compose("url: https://example.com\\ndescription: Find more info here")
56
+ external_docs = build(root)
57
+ assert external_docs.url.value == 'https://example.com'
58
+ """
59
+ return build_model(root, ExternalDocumentation, context=context)