jentic-openapi-parser 1.0.0a19__tar.gz → 1.0.0a20__tar.gz

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 (17) hide show
  1. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/PKG-INFO +50 -6
  2. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/README.md +48 -4
  3. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/pyproject.toml +3 -2
  4. jentic_openapi_parser-1.0.0a20/src/jentic/apitools/openapi/parser/backends/ruamel_ast.py +56 -0
  5. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/LICENSE +0 -0
  6. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/NOTICE +0 -0
  7. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/backends/base.py +0 -0
  8. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/backends/py.typed +0 -0
  9. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/backends/pyyaml.py +0 -0
  10. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/backends/ruamel_roundtrip.py +0 -0
  11. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/backends/ruamel_safe.py +0 -0
  12. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/core/__init__.py +0 -0
  13. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/core/exceptions.py +0 -0
  14. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/core/loader.py +0 -0
  15. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/core/openapi_parser.py +0 -0
  16. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/core/py.typed +0 -0
  17. {jentic_openapi_parser-1.0.0a19 → jentic_openapi_parser-1.0.0a20}/src/jentic/apitools/openapi/parser/core/serialization.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jentic-openapi-parser
3
- Version: 1.0.0a19
3
+ Version: 1.0.0a20
4
4
  Summary: Jentic OpenAPI Parser
5
5
  Author: Jentic
6
6
  Author-email: Jentic <hello@jentic.com>
@@ -8,7 +8,7 @@ License-Expression: Apache-2.0
8
8
  License-File: LICENSE
9
9
  License-File: NOTICE
10
10
  Requires-Dist: attrs~=25.4.0
11
- Requires-Dist: jentic-openapi-common~=1.0.0a19
11
+ Requires-Dist: jentic-openapi-common~=1.0.0a20
12
12
  Requires-Dist: pyyaml~=6.0.3
13
13
  Requires-Dist: requests~=2.32.5
14
14
  Requires-Dist: ruamel-yaml~=0.18.15
@@ -24,7 +24,7 @@ A Python library for parsing OpenAPI documents using pluggable parser backends.
24
24
 
25
25
  - **Pluggable Backend Architecture**: Support for multiple parsing strategies via entry points
26
26
  - **Multiple Input Formats**: Parse OpenAPI documents from file URIs or text strings (JSON/YAML)
27
- - **Multiple Parser Backends**: Choose from PyYAML, ruamel.yaml, or ruamel.yaml roundtrip modes
27
+ - **Multiple Parser Backends**: Choose from PyYAML, ruamel.yaml (safe/roundtrip/AST modes)
28
28
  - **Enhanced JSON Serialization**: Built-in support for datetime, UUID, Path, Decimal, Enum, and attrs classes
29
29
  - **Type Safety**: Full type hints with overloaded methods for precise return types
30
30
  - **Extensible Design**: Easy integration of third-party parser backends
@@ -53,12 +53,12 @@ doc = parser.parse("file:///path/to/openapi.yaml")
53
53
  print(doc["info"]["title"])
54
54
 
55
55
  # Parse from JSON string
56
- json_doc = '{"openapi":"3.1.0","info":{"title":"My API","version":"1.0.0"}}'
56
+ json_doc = '{"openapi":"3.1.2","info":{"title":"My API","version":"1.0.0"}}'
57
57
  doc = parser.parse(json_doc)
58
58
 
59
59
  # Parse from YAML string
60
60
  yaml_doc = """
61
- openapi: 3.1.0
61
+ openapi: 3.1.2
62
62
  info:
63
63
  title: My API
64
64
  version: 1.0.0
@@ -95,6 +95,14 @@ parser = OpenAPIParser("ruamel-roundtrip")
95
95
  doc = parser.parse("file:///path/to/openapi.yaml", return_type=CommentedMap)
96
96
  # Access line/column information
97
97
  print(doc.lc.line, doc.lc.col)
98
+
99
+ # Use ruamel.yaml AST mode (returns YAML nodes with source tracking)
100
+ from jentic.apitools.openapi.parser.backends.ruamel_ast import MappingNode
101
+ parser = OpenAPIParser("ruamel-ast")
102
+ node = parser.parse("file:///path/to/openapi.yaml", return_type=MappingNode)
103
+ # Access precise line/column for any node
104
+ for key_node, value_node in node.value:
105
+ print(f"{key_node.value} at line {key_node.start_mark.line}")
98
106
  ```
99
107
 
100
108
  ## Configuration Options
@@ -171,7 +179,7 @@ class OpenAPIParser:
171
179
 
172
180
  **Parameters:**
173
181
  - `backend`: Parser backend to use. Can be:
174
- - `str`: Name of a backend registered via entry points (e.g., "pyyaml", "ruamel-safe", "ruamel-roundtrip")
182
+ - `str`: Name of a backend registered via entry points (e.g., "pyyaml", "ruamel-safe", "ruamel-roundtrip", "ruamel-ast")
175
183
  - `BaseParserBackend`: Instance of a parser backend
176
184
  - `Type[BaseParserBackend]`: Class of a parser backend (will be instantiated)
177
185
  - Defaults to `"pyyaml"` if `None`
@@ -282,6 +290,42 @@ doc = parser.parse(content, return_type=CommentedMap)
282
290
  print(f"Line: {doc.lc.line}, Column: {doc.lc.col}")
283
291
  ```
284
292
 
293
+ ### ruamel-ast
294
+ ruamel.yaml AST mode that returns YAML nodes with complete source location tracking. Ideal for building low-level data models with precise error reporting.
295
+
296
+ **Accepts:** `text` (JSON/YAML strings), `uri` (file paths/URLs)
297
+
298
+ **Returns:** `yaml.MappingNode` (YAML AST) instead of dictionaries
299
+
300
+ ```python
301
+ from jentic.apitools.openapi.parser.backends.ruamel_ast import MappingNode
302
+
303
+ parser = OpenAPIParser("ruamel-ast")
304
+ node = parser.parse(content, return_type=MappingNode)
305
+
306
+ # Access YAML nodes with source information
307
+ assert isinstance(node, MappingNode)
308
+
309
+ # Get precise line/column information for any node
310
+ for key_node, value_node in node.value:
311
+ print(f"Key: {key_node.value}")
312
+ print(f" Line: {key_node.start_mark.line}, Column: {key_node.start_mark.column}")
313
+
314
+ # Perfect for building low-level datamodels with source tracking
315
+ # Works seamlessly with jentic-openapi-datamodels
316
+ ```
317
+
318
+ **Note:** You can also import directly from `ruamel.yaml` if preferred:
319
+ ```python
320
+ from ruamel.yaml import MappingNode # Alternative import
321
+ ```
322
+
323
+ **Use Cases:**
324
+ - Building low-level data models that preserve source locations
325
+ - Implementing precise error reporting with line/column numbers
326
+ - AST-based transformations and analysis
327
+ - Integration with validation tools that need exact source positions
328
+
285
329
  ## Testing
286
330
 
287
331
  Run the test suite:
@@ -6,7 +6,7 @@ A Python library for parsing OpenAPI documents using pluggable parser backends.
6
6
 
7
7
  - **Pluggable Backend Architecture**: Support for multiple parsing strategies via entry points
8
8
  - **Multiple Input Formats**: Parse OpenAPI documents from file URIs or text strings (JSON/YAML)
9
- - **Multiple Parser Backends**: Choose from PyYAML, ruamel.yaml, or ruamel.yaml roundtrip modes
9
+ - **Multiple Parser Backends**: Choose from PyYAML, ruamel.yaml (safe/roundtrip/AST modes)
10
10
  - **Enhanced JSON Serialization**: Built-in support for datetime, UUID, Path, Decimal, Enum, and attrs classes
11
11
  - **Type Safety**: Full type hints with overloaded methods for precise return types
12
12
  - **Extensible Design**: Easy integration of third-party parser backends
@@ -35,12 +35,12 @@ doc = parser.parse("file:///path/to/openapi.yaml")
35
35
  print(doc["info"]["title"])
36
36
 
37
37
  # Parse from JSON string
38
- json_doc = '{"openapi":"3.1.0","info":{"title":"My API","version":"1.0.0"}}'
38
+ json_doc = '{"openapi":"3.1.2","info":{"title":"My API","version":"1.0.0"}}'
39
39
  doc = parser.parse(json_doc)
40
40
 
41
41
  # Parse from YAML string
42
42
  yaml_doc = """
43
- openapi: 3.1.0
43
+ openapi: 3.1.2
44
44
  info:
45
45
  title: My API
46
46
  version: 1.0.0
@@ -77,6 +77,14 @@ parser = OpenAPIParser("ruamel-roundtrip")
77
77
  doc = parser.parse("file:///path/to/openapi.yaml", return_type=CommentedMap)
78
78
  # Access line/column information
79
79
  print(doc.lc.line, doc.lc.col)
80
+
81
+ # Use ruamel.yaml AST mode (returns YAML nodes with source tracking)
82
+ from jentic.apitools.openapi.parser.backends.ruamel_ast import MappingNode
83
+ parser = OpenAPIParser("ruamel-ast")
84
+ node = parser.parse("file:///path/to/openapi.yaml", return_type=MappingNode)
85
+ # Access precise line/column for any node
86
+ for key_node, value_node in node.value:
87
+ print(f"{key_node.value} at line {key_node.start_mark.line}")
80
88
  ```
81
89
 
82
90
  ## Configuration Options
@@ -153,7 +161,7 @@ class OpenAPIParser:
153
161
 
154
162
  **Parameters:**
155
163
  - `backend`: Parser backend to use. Can be:
156
- - `str`: Name of a backend registered via entry points (e.g., "pyyaml", "ruamel-safe", "ruamel-roundtrip")
164
+ - `str`: Name of a backend registered via entry points (e.g., "pyyaml", "ruamel-safe", "ruamel-roundtrip", "ruamel-ast")
157
165
  - `BaseParserBackend`: Instance of a parser backend
158
166
  - `Type[BaseParserBackend]`: Class of a parser backend (will be instantiated)
159
167
  - Defaults to `"pyyaml"` if `None`
@@ -264,6 +272,42 @@ doc = parser.parse(content, return_type=CommentedMap)
264
272
  print(f"Line: {doc.lc.line}, Column: {doc.lc.col}")
265
273
  ```
266
274
 
275
+ ### ruamel-ast
276
+ ruamel.yaml AST mode that returns YAML nodes with complete source location tracking. Ideal for building low-level data models with precise error reporting.
277
+
278
+ **Accepts:** `text` (JSON/YAML strings), `uri` (file paths/URLs)
279
+
280
+ **Returns:** `yaml.MappingNode` (YAML AST) instead of dictionaries
281
+
282
+ ```python
283
+ from jentic.apitools.openapi.parser.backends.ruamel_ast import MappingNode
284
+
285
+ parser = OpenAPIParser("ruamel-ast")
286
+ node = parser.parse(content, return_type=MappingNode)
287
+
288
+ # Access YAML nodes with source information
289
+ assert isinstance(node, MappingNode)
290
+
291
+ # Get precise line/column information for any node
292
+ for key_node, value_node in node.value:
293
+ print(f"Key: {key_node.value}")
294
+ print(f" Line: {key_node.start_mark.line}, Column: {key_node.start_mark.column}")
295
+
296
+ # Perfect for building low-level datamodels with source tracking
297
+ # Works seamlessly with jentic-openapi-datamodels
298
+ ```
299
+
300
+ **Note:** You can also import directly from `ruamel.yaml` if preferred:
301
+ ```python
302
+ from ruamel.yaml import MappingNode # Alternative import
303
+ ```
304
+
305
+ **Use Cases:**
306
+ - Building low-level data models that preserve source locations
307
+ - Implementing precise error reporting with line/column numbers
308
+ - AST-based transformations and analysis
309
+ - Integration with validation tools that need exact source positions
310
+
267
311
  ## Testing
268
312
 
269
313
  Run the test suite:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jentic-openapi-parser"
3
- version = "1.0.0-alpha.19"
3
+ version = "1.0.0-alpha.20"
4
4
  description = "Jentic OpenAPI Parser"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Jentic", email = "hello@jentic.com" }]
@@ -9,7 +9,7 @@ license-files = ["LICENSE", "NOTICE"]
9
9
  requires-python = ">=3.11"
10
10
  dependencies = [
11
11
  "attrs~=25.4.0",
12
- "jentic-openapi-common~=1.0.0-alpha.19",
12
+ "jentic-openapi-common~=1.0.0-alpha.20",
13
13
  "pyyaml~=6.0.3",
14
14
  "requests~=2.32.5",
15
15
  "ruamel-yaml~=0.18.15"
@@ -37,4 +37,5 @@ build-backend = "uv_build"
37
37
  pyyaml = "jentic.apitools.openapi.parser.backends.pyyaml:PyYAMLParserBackend"
38
38
  ruamel-safe = "jentic.apitools.openapi.parser.backends.ruamel_safe:RuamelSafeParserBackend"
39
39
  ruamel-roundtrip = "jentic.apitools.openapi.parser.backends.ruamel_roundtrip:RuamelRoundTripParserBackend"
40
+ ruamel-ast = "jentic.apitools.openapi.parser.backends.ruamel_ast:RuamelASTParserBackend"
40
41
 
@@ -0,0 +1,56 @@
1
+ import logging
2
+ from collections.abc import Sequence
3
+ from typing import Literal
4
+
5
+ from ruamel.yaml import MappingNode, ScalarNode, SequenceNode
6
+
7
+ from jentic.apitools.openapi.common.uri import is_uri_like
8
+ from jentic.apitools.openapi.parser.backends.ruamel_roundtrip import RuamelRoundTripParserBackend
9
+ from jentic.apitools.openapi.parser.core.loader import load_uri
10
+
11
+
12
+ __all__ = [
13
+ "RuamelASTParserBackend",
14
+ # Re-export common YAML node types for convenience
15
+ "MappingNode",
16
+ "ScalarNode",
17
+ "SequenceNode",
18
+ ]
19
+
20
+
21
+ class RuamelASTParserBackend(RuamelRoundTripParserBackend):
22
+ def parse(self, document: str, *, logger: logging.Logger | None = None) -> MappingNode: # type: ignore[override]
23
+ logger = logger or logging.getLogger(__name__)
24
+ if is_uri_like(document):
25
+ return self._parse_uri(document, logger)
26
+ return self._parse_text(document, logger)
27
+
28
+ @staticmethod
29
+ def accepts() -> Sequence[Literal["uri", "text"]]:
30
+ """Return supported input formats.
31
+
32
+ Returns:
33
+ Sequence of supported document format identifiers:
34
+ - "uri": File path or URI pointing to OpenAPI Document
35
+ - "text": String (JSON/YAML) representation
36
+ """
37
+ return ["uri", "text"]
38
+
39
+ def _parse_uri(self, uri: str, logger: logging.Logger) -> MappingNode: # type: ignore[override]
40
+ logger.debug("Starting download of %s", uri)
41
+ return self._parse_text(load_uri(uri, 5, 10, logger), logger)
42
+
43
+ def _parse_text(self, text: str, logger: logging.Logger) -> MappingNode: # type: ignore[override]
44
+ if not isinstance(text, (bytes, str)):
45
+ raise TypeError(f"Unsupported document type: {type(text)!r}")
46
+
47
+ if isinstance(text, bytes):
48
+ text = text.decode()
49
+
50
+ node: MappingNode = self.yaml.compose(text)
51
+ logger.debug("YAML document successfully parsed")
52
+
53
+ if not isinstance(node, MappingNode):
54
+ raise TypeError(f"Parsed YAML document is not a mapping: {type(node)!r}")
55
+
56
+ return node