jentic-openapi-datamodels 1.0.0a18__py3-none-any.whl → 1.0.0a20__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.0a20.dist-info/METADATA +379 -0
  67. jentic_openapi_datamodels-1.0.0a20.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.0a20.dist-info}/WHEEL +0 -0
  72. {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a20.dist-info}/licenses/LICENSE +0 -0
  73. {jentic_openapi_datamodels-1.0.0a18.dist-info → jentic_openapi_datamodels-1.0.0a20.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,129 @@
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 .oauth_flows import OAuthFlows
10
+ from .oauth_flows import build as build_oauth_flows
11
+ from .reference import Reference
12
+ from .reference import build as build_reference
13
+
14
+
15
+ __all__ = ["SecurityScheme", "build", "build_security_scheme_or_reference"]
16
+
17
+
18
+ @dataclass(frozen=True, slots=True)
19
+ class SecurityScheme:
20
+ """
21
+ Security Scheme Object representation for OpenAPI 3.1.
22
+
23
+ Defines a security scheme that can be used by operations.
24
+ The security scheme type determines which additional fields are required.
25
+
26
+ Attributes:
27
+ root_node: The top-level node representing the entire Security Scheme object in the original source file
28
+ type: REQUIRED. The type of the security scheme. Valid values: "apiKey", "http", "oauth2", "openIdConnect"
29
+ description: A short description for the security scheme. CommonMark syntax MAY be used for rich text representation
30
+ name: REQUIRED for apiKey. The name of the header, query or cookie parameter to be used
31
+ in_: REQUIRED for apiKey. The location of the API key. Valid values: "query", "header", "cookie"
32
+ scheme: REQUIRED for http. The name of the HTTP Authorization scheme (e.g., "basic", "bearer")
33
+ bearer_format: A hint to the client to identify how the bearer token is formatted (e.g., "JWT")
34
+ flows: REQUIRED for oauth2. An object containing configuration information for the flow types supported
35
+ openid_connect_url: REQUIRED for openIdConnect. OpenId Connect URL to discover OAuth2 configuration values
36
+ extensions: Specification extensions (x-* fields)
37
+ """
38
+
39
+ root_node: yaml.Node
40
+ type: FieldSource[str] | None = fixed_field()
41
+ description: FieldSource[str] | None = fixed_field()
42
+ name: FieldSource[str] | None = fixed_field()
43
+ in_: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "in"})
44
+ scheme: FieldSource[str] | None = fixed_field()
45
+ bearer_format: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "bearerFormat"})
46
+ flows: FieldSource[OAuthFlows] | None = fixed_field()
47
+ openid_connect_url: FieldSource[str] | None = fixed_field(
48
+ metadata={"yaml_name": "openIdConnectUrl"}
49
+ )
50
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
51
+
52
+
53
+ def build(
54
+ root: yaml.Node, context: Context | None = None
55
+ ) -> SecurityScheme | ValueSource[YAMLInvalidValue]:
56
+ """
57
+ Build a SecurityScheme object from a YAML node.
58
+
59
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
60
+ model that provides complete source fidelity for inspection and validation.
61
+
62
+ Args:
63
+ root: The YAML node to parse (should be a MappingNode)
64
+ context: Optional parsing context. If None, a default context will be created.
65
+
66
+ Returns:
67
+ A SecurityScheme object if the node is valid, or a ValueSource containing
68
+ the invalid data if the root is not a MappingNode (preserving the invalid data
69
+ and its source location for validation).
70
+
71
+ Example:
72
+ from ruamel.yaml import YAML
73
+ yaml = YAML()
74
+ root = yaml.compose("type: apiKey\\nname: api_key\\nin: header")
75
+ security_scheme = build(root)
76
+ assert security_scheme.type.value == 'apiKey'
77
+ """
78
+ context = context or Context()
79
+
80
+ # Use build_model for initial construction
81
+ security_scheme = build_model(root, SecurityScheme, context=context)
82
+
83
+ # If build_model returned ValueSource (invalid node), return it immediately
84
+ if not isinstance(security_scheme, SecurityScheme):
85
+ return security_scheme
86
+
87
+ # Manually handle special fields that build_model can't process (nested objects)
88
+ for key_node, value_node in root.value:
89
+ key = context.yaml_constructor.construct_yaml_str(key_node)
90
+
91
+ if key == "flows":
92
+ # Handle nested OAuthFlows object - child builder handles invalid nodes
93
+ # FieldSource will auto-unwrap ValueSource if child returns it for invalid data
94
+ flows = FieldSource(
95
+ value=build_oauth_flows(value_node, context=context),
96
+ key_node=key_node,
97
+ value_node=value_node,
98
+ )
99
+ security_scheme = replace(security_scheme, flows=flows)
100
+ break
101
+
102
+ return security_scheme
103
+
104
+
105
+ def build_security_scheme_or_reference(
106
+ node: yaml.Node, context: Context
107
+ ) -> SecurityScheme | Reference | ValueSource[YAMLInvalidValue]:
108
+ """
109
+ Build either a SecurityScheme or Reference from a YAML node.
110
+
111
+ This helper handles the polymorphic nature of OpenAPI where many fields
112
+ can contain either a SecurityScheme object or a Reference object ($ref).
113
+
114
+ Args:
115
+ node: The YAML node to parse
116
+ context: Parsing context
117
+
118
+ Returns:
119
+ A SecurityScheme, Reference, or ValueSource if the node is invalid
120
+ """
121
+ # Check if it's a reference (has $ref key)
122
+ if isinstance(node, yaml.MappingNode):
123
+ for key_node, _ in node.value:
124
+ key = context.yaml_constructor.construct_yaml_str(key_node)
125
+ if key == "$ref":
126
+ return build_reference(node, context)
127
+
128
+ # Otherwise, try to build as SecurityScheme
129
+ return build(node, context)
@@ -0,0 +1,111 @@
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 .server_variable import ServerVariable
10
+ from .server_variable import build as build_server_variable
11
+
12
+
13
+ __all__ = ["Server", "build"]
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class Server:
18
+ """
19
+ Server Object representation for OpenAPI 3.1.
20
+
21
+ An object representing a Server.
22
+
23
+ Attributes:
24
+ root_node: The top-level node representing the entire Server object in the original source file
25
+ url: REQUIRED. A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served. Variable substitutions will be made when a variable is named in {brackets}.
26
+ description: An optional string describing the host designated by the URL. CommonMark syntax MAY be used for rich text representation.
27
+ variables: A map between a variable name and its value. The value is used for substitution in the server's URL template.
28
+ extensions: Specification extensions (x-* fields)
29
+ """
30
+
31
+ root_node: yaml.Node
32
+ url: FieldSource[str] | None = fixed_field()
33
+ description: FieldSource[str] | None = fixed_field()
34
+ variables: FieldSource[dict[KeySource[str], ServerVariable]] | None = fixed_field()
35
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
36
+
37
+
38
+ def build(
39
+ root: yaml.Node, context: Context | None = None
40
+ ) -> Server | ValueSource[YAMLInvalidValue]:
41
+ """
42
+ Build a Server object from a YAML node.
43
+
44
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
45
+ model that provides complete source fidelity for inspection and validation.
46
+
47
+ Args:
48
+ root: The YAML node to parse (should be a MappingNode)
49
+ context: Optional parsing context. If None, a default context will be created.
50
+
51
+ Returns:
52
+ A Server object if the node is valid, or a ValueSource containing
53
+ the invalid data if the root is not a MappingNode (preserving the invalid data
54
+ and its source location for validation).
55
+
56
+ Example:
57
+ from ruamel.yaml import YAML
58
+ yaml = YAML()
59
+ root = yaml.compose('''
60
+ url: https://{environment}.example.com/api/v1
61
+ description: Production API server
62
+ variables:
63
+ environment:
64
+ default: production
65
+ enum:
66
+ - production
67
+ - staging
68
+ - development
69
+ description: The deployment environment
70
+ ''')
71
+ server = build(root)
72
+ assert server.url.value == 'https://{environment}.example.com/api/v1'
73
+ assert server.description.value == 'Production API server'
74
+ assert 'environment' in {k.value for k in server.variables.value.keys()}
75
+ """
76
+ context = context or Context()
77
+
78
+ # Use build_model for initial construction
79
+ server = build_model(root, Server, context=context)
80
+
81
+ # If build_model returned ValueSource (invalid node), return it immediately
82
+ if not isinstance(server, Server):
83
+ return server
84
+
85
+ # Manually handle nested variables field
86
+ for key_node, value_node in root.value:
87
+ key = context.yaml_constructor.construct_yaml_str(key_node)
88
+
89
+ if key == "variables":
90
+ # Handle variables field - map of ServerVariable objects
91
+ if isinstance(value_node, yaml.MappingNode):
92
+ variables_dict: dict[
93
+ KeySource[str], ServerVariable | ValueSource[YAMLInvalidValue]
94
+ ] = {}
95
+ for var_key_node, var_value_node in value_node.value:
96
+ var_key = context.yaml_constructor.construct_yaml_str(var_key_node)
97
+ # Build ServerVariable for each variable - child builder handles invalid nodes
98
+ variables_dict[KeySource(value=var_key, key_node=var_key_node)] = (
99
+ build_server_variable(var_value_node, context=context)
100
+ )
101
+ variables = FieldSource(
102
+ value=variables_dict, key_node=key_node, value_node=value_node
103
+ )
104
+ server = replace(server, variables=variables)
105
+ else:
106
+ # Not a mapping - preserve as-is for validation
107
+ variables = build_field_source(key_node, value_node, context)
108
+ server = replace(server, variables=variables)
109
+ break
110
+
111
+ return server
@@ -0,0 +1,70 @@
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__ = ["ServerVariable", "build"]
12
+
13
+
14
+ @dataclass(frozen=True, slots=True)
15
+ class ServerVariable:
16
+ """
17
+ Server Variable Object representation for OpenAPI 3.1.
18
+
19
+ An object representing a Server Variable for server URL template substitution.
20
+
21
+ Attributes:
22
+ root_node: The top-level node representing the entire ServerVariable object in the original source file
23
+ enum: An enumeration of string values to be used if the substitution options are from a limited set. The array SHOULD NOT be empty.
24
+ default: REQUIRED. The default value to use for substitution, which SHALL be sent if an alternate value is not supplied. If the enum is defined, the value SHOULD exist in the enum's values.
25
+ description: An optional description for the server variable. CommonMark syntax MAY be used for rich text representation.
26
+ extensions: Specification extensions (x-* fields)
27
+ """
28
+
29
+ root_node: yaml.Node
30
+ enum: FieldSource[list[ValueSource[str]]] | None = fixed_field()
31
+ default: FieldSource[str] | None = fixed_field()
32
+ description: 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
+ ) -> ServerVariable | ValueSource[YAMLInvalidValue]:
39
+ """
40
+ Build a ServerVariable 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 ServerVariable 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('''
58
+ default: production
59
+ enum:
60
+ - production
61
+ - staging
62
+ - development
63
+ description: The deployment environment
64
+ ''')
65
+ server_variable = build(root)
66
+ assert server_variable.default.value == 'production'
67
+ assert len(server_variable.enum.value) == 3
68
+ assert server_variable.enum.value[0].value == 'production'
69
+ """
70
+ return build_model(root, ServerVariable, context=context)
@@ -0,0 +1,63 @@
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 .external_documentation import ExternalDocumentation
10
+
11
+
12
+ __all__ = ["Tag", "build"]
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class Tag:
17
+ """
18
+ Tag Object representation for OpenAPI 3.1.
19
+
20
+ Adds metadata to a single tag that is used by the Operation Object. It is not mandatory
21
+ to have a Tag Object per tag defined in the Operation Object instances.
22
+
23
+ Attributes:
24
+ root_node: The top-level node representing the entire Tag object in the original source file
25
+ name: The name of the tag. REQUIRED.
26
+ description: A short description for the tag. CommonMark syntax MAY be used for rich text representation.
27
+ external_docs: Additional external documentation for this tag.
28
+ extensions: Specification extensions (x-* fields)
29
+ """
30
+
31
+ root_node: yaml.Node
32
+ name: FieldSource[str] | None = fixed_field()
33
+ description: FieldSource[str] | None = fixed_field()
34
+ external_docs: FieldSource["ExternalDocumentation"] | None = fixed_field(
35
+ metadata={"yaml_name": "externalDocs"}
36
+ )
37
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
38
+
39
+
40
+ def build(root: yaml.Node, context: Context | None = None) -> Tag | ValueSource[YAMLInvalidValue]:
41
+ """
42
+ Build a Tag object from a YAML node.
43
+
44
+ Preserves all source data as-is, regardless of type. This is a low-level/plumbing
45
+ model that provides complete source fidelity for inspection and validation.
46
+
47
+ Args:
48
+ root: The YAML node to parse (should be a MappingNode)
49
+ context: Optional parsing context. If None, a default context will be created.
50
+
51
+ Returns:
52
+ A Tag object if the node is valid, or a ValueSource containing
53
+ the invalid data if the root is not a MappingNode (preserving the invalid data
54
+ and its source location for validation).
55
+
56
+ Example:
57
+ from ruamel.yaml import YAML
58
+ yaml = YAML()
59
+ root = yaml.compose("name: pet\\ndescription: Everything about your Pets")
60
+ tag = build(root)
61
+ assert tag.name.value == 'pet'
62
+ """
63
+ return build_model(root, Tag, context=context)
@@ -0,0 +1,54 @@
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__ = ["XML", "build"]
12
+
13
+
14
+ @dataclass(frozen=True, slots=True)
15
+ class XML:
16
+ """
17
+ XML Object representation for OpenAPI 3.1.
18
+
19
+ Attributes:
20
+ root_node: The top-level node representing the entire XML object in the original source file
21
+ name: Name of the XML element
22
+ namespace: XML namespace
23
+ prefix: XML namespace prefix
24
+ attribute: Whether property is an attribute (deprecated in OpenAPI 3.2+)
25
+ wrapped: Whether array is wrapped
26
+ extensions: Specification extensions
27
+ """
28
+
29
+ root_node: yaml.Node
30
+ name: FieldSource[str] | None = fixed_field()
31
+ namespace: FieldSource[str] | None = fixed_field()
32
+ prefix: FieldSource[str] | None = fixed_field()
33
+ attribute: FieldSource[bool] | None = fixed_field()
34
+ wrapped: FieldSource[bool] | None = fixed_field()
35
+ extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
36
+
37
+
38
+ def build(root: yaml.Node, context: Context | None = None) -> XML | ValueSource[YAMLInvalidValue]:
39
+ """
40
+ Build an XML 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
+ An XML 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
+ return build_model(root, XML, context=context)