yamlstar 0.1.2__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.
- yamlstar-0.1.2/PKG-INFO +338 -0
- yamlstar-0.1.2/lib/yamlstar/__init__.py +209 -0
- yamlstar-0.1.2/lib/yamlstar.egg-info/PKG-INFO +338 -0
- yamlstar-0.1.2/lib/yamlstar.egg-info/SOURCES.txt +8 -0
- yamlstar-0.1.2/lib/yamlstar.egg-info/dependency_links.txt +1 -0
- yamlstar-0.1.2/lib/yamlstar.egg-info/top_level.txt +1 -0
- yamlstar-0.1.2/setup.cfg +7 -0
- yamlstar-0.1.2/setup.py +46 -0
- yamlstar-0.1.2/test/test_yamlstar.py +228 -0
yamlstar-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yamlstar
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Python bindings for YAMLStar - YAML 1.2 loader
|
|
5
|
+
Home-page: https://github.com/yaml/yamlstar
|
|
6
|
+
Author: Ingy döt Net
|
|
7
|
+
Author-email: ingy@ingy.net
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Requires-Python: >=3.6, <4
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
32
|
+
|
|
33
|
+
# YAMLStar Python Bindings
|
|
34
|
+
|
|
35
|
+
Python bindings for YAMLStar - a pure YAML 1.2 loader implemented in Clojure.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **YAML 1.2 Spec Compliance**: 100% compliant with YAML 1.2 core schema
|
|
40
|
+
- **Pure Implementation**: No dependencies on SnakeYAML or other external parsers
|
|
41
|
+
- **Fast Native Performance**: Uses GraalVM native-image shared library
|
|
42
|
+
- **Simple API**: Load YAML documents with a single function call
|
|
43
|
+
- **Multi-Document Support**: Load multiple YAML documents from a single string
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
### Prerequisites
|
|
48
|
+
|
|
49
|
+
First, build and install the shared library:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd ../libyamlstar
|
|
53
|
+
make native
|
|
54
|
+
sudo make install PREFIX=/usr/local
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or install to user-local directory:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd ../libyamlstar
|
|
61
|
+
make native
|
|
62
|
+
make install PREFIX=~/.local
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Install Python Package
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For development:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install -e .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import yamlstar
|
|
81
|
+
|
|
82
|
+
# Create a YAMLStar instance
|
|
83
|
+
ys = yamlstar.YAMLStar()
|
|
84
|
+
|
|
85
|
+
# Load a simple YAML string
|
|
86
|
+
data = ys.load("key: value")
|
|
87
|
+
print(data) # {'key': 'value'}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Usage Examples
|
|
91
|
+
|
|
92
|
+
### Basic Types
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import yamlstar
|
|
96
|
+
|
|
97
|
+
ys = yamlstar.YAMLStar()
|
|
98
|
+
|
|
99
|
+
# Strings
|
|
100
|
+
ys.load("hello") # 'hello'
|
|
101
|
+
|
|
102
|
+
# Integers
|
|
103
|
+
ys.load("42") # 42
|
|
104
|
+
|
|
105
|
+
# Floats
|
|
106
|
+
ys.load("3.14") # 3.14
|
|
107
|
+
|
|
108
|
+
# Booleans
|
|
109
|
+
ys.load("true") # True
|
|
110
|
+
ys.load("false") # False
|
|
111
|
+
|
|
112
|
+
# Null
|
|
113
|
+
ys.load("null") # None
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Collections
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Mappings (dictionaries)
|
|
120
|
+
data = ys.load("""
|
|
121
|
+
name: Alice
|
|
122
|
+
age: 30
|
|
123
|
+
city: Seattle
|
|
124
|
+
""")
|
|
125
|
+
# {'name': 'Alice', 'age': 30, 'city': 'Seattle'}
|
|
126
|
+
|
|
127
|
+
# Sequences (lists)
|
|
128
|
+
data = ys.load("""
|
|
129
|
+
- apple
|
|
130
|
+
- banana
|
|
131
|
+
- orange
|
|
132
|
+
""")
|
|
133
|
+
# ['apple', 'banana', 'orange']
|
|
134
|
+
|
|
135
|
+
# Flow style
|
|
136
|
+
data = ys.load("[a, b, c]")
|
|
137
|
+
# ['a', 'b', 'c']
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Nested Structures
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
data = ys.load("""
|
|
144
|
+
person:
|
|
145
|
+
name: Alice
|
|
146
|
+
age: 30
|
|
147
|
+
hobbies:
|
|
148
|
+
- reading
|
|
149
|
+
- coding
|
|
150
|
+
- hiking
|
|
151
|
+
""")
|
|
152
|
+
# {
|
|
153
|
+
# 'person': {
|
|
154
|
+
# 'name': 'Alice',
|
|
155
|
+
# 'age': 30,
|
|
156
|
+
# 'hobbies': ['reading', 'coding', 'hiking']
|
|
157
|
+
# }
|
|
158
|
+
# }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Multi-Document YAML
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Load all documents from a multi-document YAML string
|
|
165
|
+
docs = ys.load_all("""---
|
|
166
|
+
name: Document 1
|
|
167
|
+
---
|
|
168
|
+
name: Document 2
|
|
169
|
+
---
|
|
170
|
+
name: Document 3
|
|
171
|
+
""")
|
|
172
|
+
# [
|
|
173
|
+
# {'name': 'Document 1'},
|
|
174
|
+
# {'name': 'Document 2'},
|
|
175
|
+
# {'name': 'Document 3'}
|
|
176
|
+
# ]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Type Coercion
|
|
180
|
+
|
|
181
|
+
YAMLStar follows YAML 1.2 core schema type inference:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
data = ys.load("""
|
|
185
|
+
string: hello
|
|
186
|
+
integer: 42
|
|
187
|
+
float: 3.14
|
|
188
|
+
bool_true: true
|
|
189
|
+
bool_false: false
|
|
190
|
+
null_value: null
|
|
191
|
+
""")
|
|
192
|
+
# {
|
|
193
|
+
# 'string': 'hello',
|
|
194
|
+
# 'integer': 42,
|
|
195
|
+
# 'float': 3.14,
|
|
196
|
+
# 'bool_true': True,
|
|
197
|
+
# 'bool_false': False,
|
|
198
|
+
# 'null_value': None
|
|
199
|
+
# }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Error Handling
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
try:
|
|
206
|
+
data = ys.load("invalid: yaml: syntax")
|
|
207
|
+
except Exception as e:
|
|
208
|
+
print(f"Error loading YAML: {e}")
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Version Information
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
# Get YAMLStar version
|
|
215
|
+
version = ys.version()
|
|
216
|
+
print(f"YAMLStar version: {version}")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## API Reference
|
|
220
|
+
|
|
221
|
+
### `YAMLStar` Class
|
|
222
|
+
|
|
223
|
+
#### `__init__()`
|
|
224
|
+
Create a new YAMLStar instance. Each instance maintains its own GraalVM isolate.
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
ys = yamlstar.YAMLStar()
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### `load(yaml_input)`
|
|
231
|
+
Load a single YAML document.
|
|
232
|
+
|
|
233
|
+
**Parameters:**
|
|
234
|
+
- `yaml_input` (str): String containing YAML content
|
|
235
|
+
|
|
236
|
+
**Returns:**
|
|
237
|
+
- Python object representing the YAML document (dict, list, str, int, float, bool, or None)
|
|
238
|
+
|
|
239
|
+
**Raises:**
|
|
240
|
+
- `Exception` if the YAML is malformed
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
```python
|
|
244
|
+
data = ys.load("key: value")
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### `load_all(yaml_input)`
|
|
248
|
+
Load all YAML documents from a multi-document string.
|
|
249
|
+
|
|
250
|
+
**Parameters:**
|
|
251
|
+
- `yaml_input` (str): String containing one or more YAML documents
|
|
252
|
+
|
|
253
|
+
**Returns:**
|
|
254
|
+
- List of Python objects, one per YAML document
|
|
255
|
+
|
|
256
|
+
**Raises:**
|
|
257
|
+
- `Exception` if the YAML is malformed
|
|
258
|
+
|
|
259
|
+
**Example:**
|
|
260
|
+
```python
|
|
261
|
+
docs = ys.load_all("---\ndoc1\n---\ndoc2")
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### `version()`
|
|
265
|
+
Get the YAMLStar version string.
|
|
266
|
+
|
|
267
|
+
**Returns:**
|
|
268
|
+
- str: Version string
|
|
269
|
+
|
|
270
|
+
**Example:**
|
|
271
|
+
```python
|
|
272
|
+
version = ys.version()
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Development
|
|
276
|
+
|
|
277
|
+
### Running Tests
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Run all tests
|
|
281
|
+
make test
|
|
282
|
+
|
|
283
|
+
# Run only pytest tests
|
|
284
|
+
make test-pytest
|
|
285
|
+
|
|
286
|
+
# Run only FFI tests
|
|
287
|
+
make test-ffi
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Building Distribution
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Build source distribution
|
|
294
|
+
make dist
|
|
295
|
+
|
|
296
|
+
# Build and install in development mode
|
|
297
|
+
make install
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Requirements
|
|
301
|
+
|
|
302
|
+
- **Python**: 3.6 or higher
|
|
303
|
+
- **libyamlstar**: Shared library (installed separately)
|
|
304
|
+
- **System**: Linux or macOS
|
|
305
|
+
|
|
306
|
+
## Library Search Path
|
|
307
|
+
|
|
308
|
+
The package searches for `libyamlstar.so` (or `.dylib` on macOS) in:
|
|
309
|
+
|
|
310
|
+
1. Development path (relative to package)
|
|
311
|
+
2. Directories in `LD_LIBRARY_PATH` environment variable
|
|
312
|
+
3. `/usr/local/lib` (default install location)
|
|
313
|
+
4. `~/.local/lib` (user-local install location)
|
|
314
|
+
|
|
315
|
+
## Comparison to PyYAML
|
|
316
|
+
|
|
317
|
+
| Feature | YAMLStar | PyYAML |
|
|
318
|
+
|---------|----------|--------|
|
|
319
|
+
| YAML Version | 1.2 | 1.1 |
|
|
320
|
+
| Implementation | Pure Clojure | C + Python |
|
|
321
|
+
| Type Inference | YAML 1.2 core schema | YAML 1.1 + custom |
|
|
322
|
+
| Native Performance | Yes (GraalVM) | Yes (C extension) |
|
|
323
|
+
| Dependencies | libyamlstar.so | None |
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT License - See [License](License) file
|
|
328
|
+
|
|
329
|
+
## Credits
|
|
330
|
+
|
|
331
|
+
Created by Ingy döt Net, inventor of YAML.
|
|
332
|
+
|
|
333
|
+
YAMLStar is built on the YAML Reference Parser (pure Clojure implementation).
|
|
334
|
+
|
|
335
|
+
## Links
|
|
336
|
+
|
|
337
|
+
- **GitHub**: https://github.com/yaml/yamlstar
|
|
338
|
+
- **YAML Specification**: https://yaml.org/spec/1.2/spec.html
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Copyright 2024 yaml.org
|
|
2
|
+
# MIT License
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Python binding/API for the libyamlstar shared library.
|
|
6
|
+
|
|
7
|
+
This module provides a Python interface to YAMLStar, a pure YAML 1.2 loader.
|
|
8
|
+
The YAMLStar class has methods for loading YAML documents and converting
|
|
9
|
+
them to Python objects.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
# Version matching the yamlstar shared library
|
|
13
|
+
yamlstar_version = '0.1.2'
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
import ctypes
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
# Require Python 3.6 or greater:
|
|
21
|
+
assert sys.version_info >= (3, 6), \
|
|
22
|
+
"Python 3.6 or greater required for 'yamlstar'."
|
|
23
|
+
|
|
24
|
+
# Find the libyamlstar shared library file path:
|
|
25
|
+
def find_libyamlstar_path():
|
|
26
|
+
# Confirm platform and determine file extension:
|
|
27
|
+
if sys.platform == 'linux':
|
|
28
|
+
so = 'so'
|
|
29
|
+
elif sys.platform == 'darwin':
|
|
30
|
+
so = 'dylib'
|
|
31
|
+
elif sys.platform == 'win32':
|
|
32
|
+
so = 'dll'
|
|
33
|
+
else:
|
|
34
|
+
raise Exception(
|
|
35
|
+
"Unsupported platform '%s' for yamlstar." % sys.platform)
|
|
36
|
+
|
|
37
|
+
# We currently bind to an exact version of libyamlstar.
|
|
38
|
+
# eg 'libyamlstar.so.0.1.2-SNAPSHOT'
|
|
39
|
+
libyamlstar_name = \
|
|
40
|
+
"libyamlstar.%s.%s" % (so, yamlstar_version)
|
|
41
|
+
|
|
42
|
+
# Use LD_LIBRARY_PATH to find libyamlstar shared library, or default to
|
|
43
|
+
# '/usr/local/lib' (where it is installed by default):
|
|
44
|
+
ld_library_path = os.environ.get('LD_LIBRARY_PATH')
|
|
45
|
+
ld_library_paths = ld_library_path.split(':') if ld_library_path else []
|
|
46
|
+
ld_library_paths.append('/usr/local/lib')
|
|
47
|
+
ld_library_paths.append(os.environ.get('HOME') + '/.local/lib')
|
|
48
|
+
|
|
49
|
+
# Also check relative to this file (for development)
|
|
50
|
+
lib_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), '..', 'libyamlstar', 'lib')
|
|
51
|
+
lib_path = os.path.abspath(lib_path)
|
|
52
|
+
ld_library_paths.insert(0, lib_path)
|
|
53
|
+
|
|
54
|
+
libyamlstar_path = None
|
|
55
|
+
for path in ld_library_paths:
|
|
56
|
+
full_path = os.path.join(path, libyamlstar_name)
|
|
57
|
+
if os.path.isfile(full_path):
|
|
58
|
+
libyamlstar_path = full_path
|
|
59
|
+
break
|
|
60
|
+
|
|
61
|
+
if not libyamlstar_path:
|
|
62
|
+
raise Exception(
|
|
63
|
+
"""\
|
|
64
|
+
Shared library file '%s' not found
|
|
65
|
+
Search paths: %s
|
|
66
|
+
Build with: cd libyamlstar && make native
|
|
67
|
+
""" % (libyamlstar_name, ':'.join(ld_library_paths)))
|
|
68
|
+
|
|
69
|
+
return libyamlstar_path
|
|
70
|
+
|
|
71
|
+
# Load libyamlstar shared library:
|
|
72
|
+
libyamlstar = ctypes.CDLL(find_libyamlstar_path())
|
|
73
|
+
|
|
74
|
+
# Create bindings to library functions:
|
|
75
|
+
yamlstar_load = libyamlstar.yamlstar_load
|
|
76
|
+
yamlstar_load.restype = ctypes.c_char_p
|
|
77
|
+
|
|
78
|
+
yamlstar_load_all = libyamlstar.yamlstar_load_all
|
|
79
|
+
yamlstar_load_all.restype = ctypes.c_char_p
|
|
80
|
+
|
|
81
|
+
yamlstar_version_fn = libyamlstar.yamlstar_version
|
|
82
|
+
yamlstar_version_fn.restype = ctypes.c_char_p
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# The YAMLStar class is the main user facing API for this module.
|
|
86
|
+
class YAMLStar():
|
|
87
|
+
"""
|
|
88
|
+
Interface with the libyamlstar shared library.
|
|
89
|
+
|
|
90
|
+
Usage:
|
|
91
|
+
import yamlstar
|
|
92
|
+
ys = yamlstar.YAMLStar()
|
|
93
|
+
data = ys.load("key: value")
|
|
94
|
+
# Returns: {'key': 'value'}
|
|
95
|
+
|
|
96
|
+
docs = ys.load_all("---\\ndoc1\\n---\\ndoc2")
|
|
97
|
+
# Returns: ['doc1', 'doc2']
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
# YAMLStar instance constructor:
|
|
101
|
+
def __init__(self):
|
|
102
|
+
# Create a new GraalVM isolatethread for life of the YAMLStar instance:
|
|
103
|
+
self.isolatethread = ctypes.c_void_p()
|
|
104
|
+
|
|
105
|
+
# Create a new GraalVM isolate:
|
|
106
|
+
rc = libyamlstar.graal_create_isolate(
|
|
107
|
+
None,
|
|
108
|
+
None,
|
|
109
|
+
ctypes.byref(self.isolatethread),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if rc != 0:
|
|
113
|
+
raise Exception("Failed to create isolate")
|
|
114
|
+
|
|
115
|
+
# Load a single YAML document and return the result:
|
|
116
|
+
def load(self, yaml_input):
|
|
117
|
+
"""
|
|
118
|
+
Load a single YAML document.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
yaml_input: String containing YAML content
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Python object representing the YAML document
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
Exception if the YAML is malformed
|
|
128
|
+
"""
|
|
129
|
+
# Reset any previous error:
|
|
130
|
+
self.error = None
|
|
131
|
+
|
|
132
|
+
# Call 'yamlstar_load' function in libyamlstar shared library:
|
|
133
|
+
data_json = yamlstar_load(
|
|
134
|
+
self.isolatethread,
|
|
135
|
+
ctypes.c_char_p(bytes(yaml_input, "utf8")),
|
|
136
|
+
).decode()
|
|
137
|
+
|
|
138
|
+
# Decode the JSON response:
|
|
139
|
+
resp = json.loads(data_json)
|
|
140
|
+
|
|
141
|
+
# Check for libyamlstar error in JSON response:
|
|
142
|
+
self.error = resp.get('error')
|
|
143
|
+
if self.error:
|
|
144
|
+
raise Exception(self.error['cause'])
|
|
145
|
+
|
|
146
|
+
# Get the response object from loading the YAML string:
|
|
147
|
+
if 'data' not in resp:
|
|
148
|
+
raise Exception("Unexpected response from 'libyamlstar'")
|
|
149
|
+
data = resp.get('data')
|
|
150
|
+
|
|
151
|
+
# Return the response object:
|
|
152
|
+
return data
|
|
153
|
+
|
|
154
|
+
# Load all YAML documents and return the results:
|
|
155
|
+
def load_all(self, yaml_input):
|
|
156
|
+
"""
|
|
157
|
+
Load all YAML documents from a multi-document string.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
yaml_input: String containing one or more YAML documents
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
List of Python objects, one per YAML document
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
Exception if the YAML is malformed
|
|
167
|
+
"""
|
|
168
|
+
# Reset any previous error:
|
|
169
|
+
self.error = None
|
|
170
|
+
|
|
171
|
+
# Call 'yamlstar_load_all' function in libyamlstar shared library:
|
|
172
|
+
data_json = yamlstar_load_all(
|
|
173
|
+
self.isolatethread,
|
|
174
|
+
ctypes.c_char_p(bytes(yaml_input, "utf8")),
|
|
175
|
+
).decode()
|
|
176
|
+
|
|
177
|
+
# Decode the JSON response:
|
|
178
|
+
resp = json.loads(data_json)
|
|
179
|
+
|
|
180
|
+
# Check for libyamlstar error in JSON response:
|
|
181
|
+
self.error = resp.get('error')
|
|
182
|
+
if self.error:
|
|
183
|
+
raise Exception(self.error['cause'])
|
|
184
|
+
|
|
185
|
+
# Get the response object from loading the YAML string:
|
|
186
|
+
if 'data' not in resp:
|
|
187
|
+
raise Exception("Unexpected response from 'libyamlstar'")
|
|
188
|
+
data = resp.get('data')
|
|
189
|
+
|
|
190
|
+
# Return the response object:
|
|
191
|
+
return data
|
|
192
|
+
|
|
193
|
+
# Get the YAMLStar version:
|
|
194
|
+
def version(self):
|
|
195
|
+
"""
|
|
196
|
+
Get the YAMLStar version string.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Version string
|
|
200
|
+
"""
|
|
201
|
+
return yamlstar_version_fn(self.isolatethread).decode()
|
|
202
|
+
|
|
203
|
+
# YAMLStar instance destructor:
|
|
204
|
+
def __del__(self):
|
|
205
|
+
# Tear down the isolate thread to free resources:
|
|
206
|
+
if hasattr(self, 'isolatethread'):
|
|
207
|
+
rc = libyamlstar.graal_tear_down_isolate(self.isolatethread)
|
|
208
|
+
if rc != 0:
|
|
209
|
+
raise Exception("Failed to tear down isolate")
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yamlstar
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Python bindings for YAMLStar - YAML 1.2 loader
|
|
5
|
+
Home-page: https://github.com/yaml/yamlstar
|
|
6
|
+
Author: Ingy döt Net
|
|
7
|
+
Author-email: ingy@ingy.net
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Requires-Python: >=3.6, <4
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
32
|
+
|
|
33
|
+
# YAMLStar Python Bindings
|
|
34
|
+
|
|
35
|
+
Python bindings for YAMLStar - a pure YAML 1.2 loader implemented in Clojure.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **YAML 1.2 Spec Compliance**: 100% compliant with YAML 1.2 core schema
|
|
40
|
+
- **Pure Implementation**: No dependencies on SnakeYAML or other external parsers
|
|
41
|
+
- **Fast Native Performance**: Uses GraalVM native-image shared library
|
|
42
|
+
- **Simple API**: Load YAML documents with a single function call
|
|
43
|
+
- **Multi-Document Support**: Load multiple YAML documents from a single string
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
### Prerequisites
|
|
48
|
+
|
|
49
|
+
First, build and install the shared library:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd ../libyamlstar
|
|
53
|
+
make native
|
|
54
|
+
sudo make install PREFIX=/usr/local
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or install to user-local directory:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd ../libyamlstar
|
|
61
|
+
make native
|
|
62
|
+
make install PREFIX=~/.local
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Install Python Package
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For development:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install -e .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import yamlstar
|
|
81
|
+
|
|
82
|
+
# Create a YAMLStar instance
|
|
83
|
+
ys = yamlstar.YAMLStar()
|
|
84
|
+
|
|
85
|
+
# Load a simple YAML string
|
|
86
|
+
data = ys.load("key: value")
|
|
87
|
+
print(data) # {'key': 'value'}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Usage Examples
|
|
91
|
+
|
|
92
|
+
### Basic Types
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import yamlstar
|
|
96
|
+
|
|
97
|
+
ys = yamlstar.YAMLStar()
|
|
98
|
+
|
|
99
|
+
# Strings
|
|
100
|
+
ys.load("hello") # 'hello'
|
|
101
|
+
|
|
102
|
+
# Integers
|
|
103
|
+
ys.load("42") # 42
|
|
104
|
+
|
|
105
|
+
# Floats
|
|
106
|
+
ys.load("3.14") # 3.14
|
|
107
|
+
|
|
108
|
+
# Booleans
|
|
109
|
+
ys.load("true") # True
|
|
110
|
+
ys.load("false") # False
|
|
111
|
+
|
|
112
|
+
# Null
|
|
113
|
+
ys.load("null") # None
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Collections
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Mappings (dictionaries)
|
|
120
|
+
data = ys.load("""
|
|
121
|
+
name: Alice
|
|
122
|
+
age: 30
|
|
123
|
+
city: Seattle
|
|
124
|
+
""")
|
|
125
|
+
# {'name': 'Alice', 'age': 30, 'city': 'Seattle'}
|
|
126
|
+
|
|
127
|
+
# Sequences (lists)
|
|
128
|
+
data = ys.load("""
|
|
129
|
+
- apple
|
|
130
|
+
- banana
|
|
131
|
+
- orange
|
|
132
|
+
""")
|
|
133
|
+
# ['apple', 'banana', 'orange']
|
|
134
|
+
|
|
135
|
+
# Flow style
|
|
136
|
+
data = ys.load("[a, b, c]")
|
|
137
|
+
# ['a', 'b', 'c']
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Nested Structures
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
data = ys.load("""
|
|
144
|
+
person:
|
|
145
|
+
name: Alice
|
|
146
|
+
age: 30
|
|
147
|
+
hobbies:
|
|
148
|
+
- reading
|
|
149
|
+
- coding
|
|
150
|
+
- hiking
|
|
151
|
+
""")
|
|
152
|
+
# {
|
|
153
|
+
# 'person': {
|
|
154
|
+
# 'name': 'Alice',
|
|
155
|
+
# 'age': 30,
|
|
156
|
+
# 'hobbies': ['reading', 'coding', 'hiking']
|
|
157
|
+
# }
|
|
158
|
+
# }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Multi-Document YAML
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Load all documents from a multi-document YAML string
|
|
165
|
+
docs = ys.load_all("""---
|
|
166
|
+
name: Document 1
|
|
167
|
+
---
|
|
168
|
+
name: Document 2
|
|
169
|
+
---
|
|
170
|
+
name: Document 3
|
|
171
|
+
""")
|
|
172
|
+
# [
|
|
173
|
+
# {'name': 'Document 1'},
|
|
174
|
+
# {'name': 'Document 2'},
|
|
175
|
+
# {'name': 'Document 3'}
|
|
176
|
+
# ]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Type Coercion
|
|
180
|
+
|
|
181
|
+
YAMLStar follows YAML 1.2 core schema type inference:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
data = ys.load("""
|
|
185
|
+
string: hello
|
|
186
|
+
integer: 42
|
|
187
|
+
float: 3.14
|
|
188
|
+
bool_true: true
|
|
189
|
+
bool_false: false
|
|
190
|
+
null_value: null
|
|
191
|
+
""")
|
|
192
|
+
# {
|
|
193
|
+
# 'string': 'hello',
|
|
194
|
+
# 'integer': 42,
|
|
195
|
+
# 'float': 3.14,
|
|
196
|
+
# 'bool_true': True,
|
|
197
|
+
# 'bool_false': False,
|
|
198
|
+
# 'null_value': None
|
|
199
|
+
# }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Error Handling
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
try:
|
|
206
|
+
data = ys.load("invalid: yaml: syntax")
|
|
207
|
+
except Exception as e:
|
|
208
|
+
print(f"Error loading YAML: {e}")
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Version Information
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
# Get YAMLStar version
|
|
215
|
+
version = ys.version()
|
|
216
|
+
print(f"YAMLStar version: {version}")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## API Reference
|
|
220
|
+
|
|
221
|
+
### `YAMLStar` Class
|
|
222
|
+
|
|
223
|
+
#### `__init__()`
|
|
224
|
+
Create a new YAMLStar instance. Each instance maintains its own GraalVM isolate.
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
ys = yamlstar.YAMLStar()
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### `load(yaml_input)`
|
|
231
|
+
Load a single YAML document.
|
|
232
|
+
|
|
233
|
+
**Parameters:**
|
|
234
|
+
- `yaml_input` (str): String containing YAML content
|
|
235
|
+
|
|
236
|
+
**Returns:**
|
|
237
|
+
- Python object representing the YAML document (dict, list, str, int, float, bool, or None)
|
|
238
|
+
|
|
239
|
+
**Raises:**
|
|
240
|
+
- `Exception` if the YAML is malformed
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
```python
|
|
244
|
+
data = ys.load("key: value")
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### `load_all(yaml_input)`
|
|
248
|
+
Load all YAML documents from a multi-document string.
|
|
249
|
+
|
|
250
|
+
**Parameters:**
|
|
251
|
+
- `yaml_input` (str): String containing one or more YAML documents
|
|
252
|
+
|
|
253
|
+
**Returns:**
|
|
254
|
+
- List of Python objects, one per YAML document
|
|
255
|
+
|
|
256
|
+
**Raises:**
|
|
257
|
+
- `Exception` if the YAML is malformed
|
|
258
|
+
|
|
259
|
+
**Example:**
|
|
260
|
+
```python
|
|
261
|
+
docs = ys.load_all("---\ndoc1\n---\ndoc2")
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### `version()`
|
|
265
|
+
Get the YAMLStar version string.
|
|
266
|
+
|
|
267
|
+
**Returns:**
|
|
268
|
+
- str: Version string
|
|
269
|
+
|
|
270
|
+
**Example:**
|
|
271
|
+
```python
|
|
272
|
+
version = ys.version()
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Development
|
|
276
|
+
|
|
277
|
+
### Running Tests
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Run all tests
|
|
281
|
+
make test
|
|
282
|
+
|
|
283
|
+
# Run only pytest tests
|
|
284
|
+
make test-pytest
|
|
285
|
+
|
|
286
|
+
# Run only FFI tests
|
|
287
|
+
make test-ffi
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Building Distribution
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Build source distribution
|
|
294
|
+
make dist
|
|
295
|
+
|
|
296
|
+
# Build and install in development mode
|
|
297
|
+
make install
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Requirements
|
|
301
|
+
|
|
302
|
+
- **Python**: 3.6 or higher
|
|
303
|
+
- **libyamlstar**: Shared library (installed separately)
|
|
304
|
+
- **System**: Linux or macOS
|
|
305
|
+
|
|
306
|
+
## Library Search Path
|
|
307
|
+
|
|
308
|
+
The package searches for `libyamlstar.so` (or `.dylib` on macOS) in:
|
|
309
|
+
|
|
310
|
+
1. Development path (relative to package)
|
|
311
|
+
2. Directories in `LD_LIBRARY_PATH` environment variable
|
|
312
|
+
3. `/usr/local/lib` (default install location)
|
|
313
|
+
4. `~/.local/lib` (user-local install location)
|
|
314
|
+
|
|
315
|
+
## Comparison to PyYAML
|
|
316
|
+
|
|
317
|
+
| Feature | YAMLStar | PyYAML |
|
|
318
|
+
|---------|----------|--------|
|
|
319
|
+
| YAML Version | 1.2 | 1.1 |
|
|
320
|
+
| Implementation | Pure Clojure | C + Python |
|
|
321
|
+
| Type Inference | YAML 1.2 core schema | YAML 1.1 + custom |
|
|
322
|
+
| Native Performance | Yes (GraalVM) | Yes (C extension) |
|
|
323
|
+
| Dependencies | libyamlstar.so | None |
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT License - See [License](License) file
|
|
328
|
+
|
|
329
|
+
## Credits
|
|
330
|
+
|
|
331
|
+
Created by Ingy döt Net, inventor of YAML.
|
|
332
|
+
|
|
333
|
+
YAMLStar is built on the YAML Reference Parser (pure Clojure implementation).
|
|
334
|
+
|
|
335
|
+
## Links
|
|
336
|
+
|
|
337
|
+
- **GitHub**: https://github.com/yaml/yamlstar
|
|
338
|
+
- **YAML Specification**: https://yaml.org/spec/1.2/spec.html
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
yamlstar
|
yamlstar-0.1.2/setup.cfg
ADDED
yamlstar-0.1.2/setup.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from setuptools import setup
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
# Read version from ../Meta file
|
|
8
|
+
meta_file = Path(__file__).parent.parent / 'Meta'
|
|
9
|
+
meta_content = meta_file.read_text()
|
|
10
|
+
match = re.search(r'^version:\s*(.+)$', meta_content, re.MULTILINE)
|
|
11
|
+
version = match.group(1) if match else None
|
|
12
|
+
|
|
13
|
+
# Validate version format
|
|
14
|
+
if not version or not re.match(r'^\d+\.\d+\.\d+', version):
|
|
15
|
+
raise ValueError(f"Invalid or missing version in Meta file: {version}")
|
|
16
|
+
|
|
17
|
+
setup(
|
|
18
|
+
name = 'yamlstar',
|
|
19
|
+
version = version,
|
|
20
|
+
description = 'Python bindings for YAMLStar - YAML 1.2 loader',
|
|
21
|
+
long_description = open('ReadMe.md').read() if __name__ == '__main__' else '',
|
|
22
|
+
long_description_content_type = 'text/markdown',
|
|
23
|
+
author = 'Ingy döt Net',
|
|
24
|
+
author_email = 'ingy@ingy.net',
|
|
25
|
+
url = 'https://github.com/yaml/yamlstar',
|
|
26
|
+
license = 'MIT',
|
|
27
|
+
packages = ['yamlstar'],
|
|
28
|
+
package_dir = {'': 'lib'},
|
|
29
|
+
python_requires = '>=3.6, <4',
|
|
30
|
+
install_requires = [],
|
|
31
|
+
setup_requires = ['wheel'],
|
|
32
|
+
classifiers = [
|
|
33
|
+
'Development Status :: 3 - Alpha',
|
|
34
|
+
'Intended Audience :: Developers',
|
|
35
|
+
'License :: OSI Approved :: MIT License',
|
|
36
|
+
'Programming Language :: Python :: 3',
|
|
37
|
+
'Programming Language :: Python :: 3.6',
|
|
38
|
+
'Programming Language :: Python :: 3.7',
|
|
39
|
+
'Programming Language :: Python :: 3.8',
|
|
40
|
+
'Programming Language :: Python :: 3.9',
|
|
41
|
+
'Programming Language :: Python :: 3.10',
|
|
42
|
+
'Programming Language :: Python :: 3.11',
|
|
43
|
+
'Programming Language :: Python :: 3.12',
|
|
44
|
+
'Topic :: Software Development :: Libraries',
|
|
45
|
+
],
|
|
46
|
+
)
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for yamlstar Python package.
|
|
3
|
+
"""
|
|
4
|
+
import pytest
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
# Add lib directory to path for testing
|
|
9
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'lib'))
|
|
10
|
+
|
|
11
|
+
import yamlstar
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def ys():
|
|
16
|
+
"""Create a YAMLStar instance for testing."""
|
|
17
|
+
return yamlstar.YAMLStar()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_load_simple_scalar(ys):
|
|
21
|
+
"""Test loading a simple scalar value."""
|
|
22
|
+
result = ys.load("hello")
|
|
23
|
+
assert result == "hello"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_load_integer(ys):
|
|
27
|
+
"""Test loading an integer."""
|
|
28
|
+
result = ys.load("42")
|
|
29
|
+
assert result == 42
|
|
30
|
+
assert isinstance(result, int)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_load_float(ys):
|
|
34
|
+
"""Test loading a float."""
|
|
35
|
+
result = ys.load("3.14")
|
|
36
|
+
assert result == 3.14
|
|
37
|
+
assert isinstance(result, float)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_load_boolean_true(ys):
|
|
41
|
+
"""Test loading boolean true."""
|
|
42
|
+
result = ys.load("true")
|
|
43
|
+
assert result is True
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_load_boolean_false(ys):
|
|
47
|
+
"""Test loading boolean false."""
|
|
48
|
+
result = ys.load("false")
|
|
49
|
+
assert result is False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_load_null(ys):
|
|
53
|
+
"""Test loading null value."""
|
|
54
|
+
result = ys.load("null")
|
|
55
|
+
assert result is None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_load_simple_mapping(ys):
|
|
59
|
+
"""Test loading a simple mapping."""
|
|
60
|
+
result = ys.load("key: value")
|
|
61
|
+
assert result == {"key": "value"}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_load_nested_mapping(ys):
|
|
65
|
+
"""Test loading nested mappings."""
|
|
66
|
+
yaml_str = """
|
|
67
|
+
outer:
|
|
68
|
+
inner: value
|
|
69
|
+
"""
|
|
70
|
+
result = ys.load(yaml_str)
|
|
71
|
+
assert result == {"outer": {"inner": "value"}}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_load_mapping_multiple_keys(ys):
|
|
75
|
+
"""Test loading a mapping with multiple keys."""
|
|
76
|
+
yaml_str = """
|
|
77
|
+
key1: value1
|
|
78
|
+
key2: value2
|
|
79
|
+
key3: value3
|
|
80
|
+
"""
|
|
81
|
+
result = ys.load(yaml_str)
|
|
82
|
+
assert result == {
|
|
83
|
+
"key1": "value1",
|
|
84
|
+
"key2": "value2",
|
|
85
|
+
"key3": "value3"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_load_simple_sequence(ys):
|
|
90
|
+
"""Test loading a simple sequence."""
|
|
91
|
+
yaml_str = """
|
|
92
|
+
- item1
|
|
93
|
+
- item2
|
|
94
|
+
- item3
|
|
95
|
+
"""
|
|
96
|
+
result = ys.load(yaml_str)
|
|
97
|
+
assert result == ["item1", "item2", "item3"]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_load_flow_sequence(ys):
|
|
101
|
+
"""Test loading flow-style sequence."""
|
|
102
|
+
result = ys.load("[a, b, c]")
|
|
103
|
+
assert result == ["a", "b", "c"]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_load_type_coercion(ys):
|
|
107
|
+
"""Test YAML 1.2 type coercion."""
|
|
108
|
+
yaml_str = """
|
|
109
|
+
string: hello
|
|
110
|
+
integer: 42
|
|
111
|
+
float: 3.14
|
|
112
|
+
bool_true: true
|
|
113
|
+
bool_false: false
|
|
114
|
+
null_value: null
|
|
115
|
+
"""
|
|
116
|
+
result = ys.load(yaml_str)
|
|
117
|
+
assert result == {
|
|
118
|
+
"string": "hello",
|
|
119
|
+
"integer": 42,
|
|
120
|
+
"float": 3.14,
|
|
121
|
+
"bool_true": True,
|
|
122
|
+
"bool_false": False,
|
|
123
|
+
"null_value": None
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_load_sequence_of_mappings(ys):
|
|
128
|
+
"""Test loading a sequence of mappings."""
|
|
129
|
+
yaml_str = """
|
|
130
|
+
- name: Alice
|
|
131
|
+
age: 30
|
|
132
|
+
- name: Bob
|
|
133
|
+
age: 25
|
|
134
|
+
"""
|
|
135
|
+
result = ys.load(yaml_str)
|
|
136
|
+
assert result == [
|
|
137
|
+
{"name": "Alice", "age": 30},
|
|
138
|
+
{"name": "Bob", "age": 25}
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_load_mapping_with_sequence_values(ys):
|
|
143
|
+
"""Test loading a mapping with sequence values."""
|
|
144
|
+
yaml_str = """
|
|
145
|
+
fruits:
|
|
146
|
+
- apple
|
|
147
|
+
- banana
|
|
148
|
+
colors:
|
|
149
|
+
- red
|
|
150
|
+
- blue
|
|
151
|
+
"""
|
|
152
|
+
result = ys.load(yaml_str)
|
|
153
|
+
assert result == {
|
|
154
|
+
"fruits": ["apple", "banana"],
|
|
155
|
+
"colors": ["red", "blue"]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_load_all_single_document(ys):
|
|
160
|
+
"""Test load_all with a single document."""
|
|
161
|
+
result = ys.load_all("hello")
|
|
162
|
+
assert result == ["hello"]
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_load_all_multiple_documents(ys):
|
|
166
|
+
"""Test load_all with multiple documents."""
|
|
167
|
+
yaml_str = """---
|
|
168
|
+
doc1
|
|
169
|
+
---
|
|
170
|
+
doc2
|
|
171
|
+
---
|
|
172
|
+
doc3"""
|
|
173
|
+
result = ys.load_all(yaml_str)
|
|
174
|
+
assert result == ["doc1", "doc2", "doc3"]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_load_all_with_explicit_markers(ys):
|
|
178
|
+
"""Test load_all with explicit document markers."""
|
|
179
|
+
yaml_str = """---
|
|
180
|
+
a: 1
|
|
181
|
+
...
|
|
182
|
+
---
|
|
183
|
+
b: 2
|
|
184
|
+
..."""
|
|
185
|
+
result = ys.load_all(yaml_str)
|
|
186
|
+
assert result == [{"a": 1}, {"b": 2}]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_version(ys):
|
|
190
|
+
"""Test getting the version string."""
|
|
191
|
+
version = ys.version()
|
|
192
|
+
assert isinstance(version, str)
|
|
193
|
+
assert len(version) > 0
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def test_error_handling_malformed_yaml(ys):
|
|
197
|
+
"""Test that malformed YAML raises an exception."""
|
|
198
|
+
# Unclosed quote is truly malformed
|
|
199
|
+
malformed_yaml = 'key: "unclosed'
|
|
200
|
+
with pytest.raises(Exception):
|
|
201
|
+
ys.load(malformed_yaml)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_empty_document(ys):
|
|
205
|
+
"""Test loading an empty document."""
|
|
206
|
+
result = ys.load("")
|
|
207
|
+
assert result is None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_whitespace_only(ys):
|
|
211
|
+
"""Test loading whitespace-only document."""
|
|
212
|
+
result = ys.load(" \n \n ")
|
|
213
|
+
assert result is None
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def test_quoted_strings(ys):
|
|
217
|
+
"""Test loading quoted strings."""
|
|
218
|
+
result1 = ys.load("'hello world'")
|
|
219
|
+
assert result1 == "hello world"
|
|
220
|
+
|
|
221
|
+
result2 = ys.load('"hello world"')
|
|
222
|
+
assert result2 == "hello world"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_module_version():
|
|
226
|
+
"""Test that the module has a version attribute."""
|
|
227
|
+
assert hasattr(yamlstar, 'yamlstar_version')
|
|
228
|
+
assert isinstance(yamlstar.yamlstar_version, str)
|