toons 0.4.0__tar.gz → 0.5.0__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 (66) hide show
  1. {toons-0.4.0 → toons-0.5.0}/.github/workflows/CI.yml +10 -10
  2. {toons-0.4.0 → toons-0.5.0}/Cargo.lock +21 -60
  3. {toons-0.4.0 → toons-0.5.0}/Cargo.toml +1 -1
  4. {toons-0.4.0 → toons-0.5.0}/PKG-INFO +13 -11
  5. {toons-0.4.0 → toons-0.5.0}/README.md +12 -10
  6. {toons-0.4.0 → toons-0.5.0}/docs/README.md +1 -1
  7. {toons-0.4.0 → toons-0.5.0}/docs/api-reference.md +48 -16
  8. {toons-0.4.0 → toons-0.5.0}/docs/examples.md +1 -1
  9. {toons-0.4.0 → toons-0.5.0}/docs/index.md +2 -2
  10. {toons-0.4.0 → toons-0.5.0}/docs/testing.md +2 -2
  11. {toons-0.4.0 → toons-0.5.0}/src/lib.rs +76 -19
  12. toons-0.5.0/src/toon/deserialize.rs +1176 -0
  13. toons-0.5.0/src/toon/mod.rs +100 -0
  14. toons-0.5.0/src/toon/serialize.rs +1186 -0
  15. toons-0.5.0/tests/integration/README.md +229 -0
  16. toons-0.5.0/tests/integration/conftest.py +62 -0
  17. toons-0.5.0/tests/integration/fixtures/decode/arrays-nested.json +217 -0
  18. toons-0.5.0/tests/integration/fixtures/decode/arrays-primitive.json +111 -0
  19. toons-0.5.0/tests/integration/fixtures/decode/arrays-tabular.json +74 -0
  20. toons-0.5.0/tests/integration/fixtures/decode/blank-lines.json +153 -0
  21. toons-0.5.0/tests/integration/fixtures/decode/delimiters.json +246 -0
  22. toons-0.5.0/tests/integration/fixtures/decode/indentation-errors.json +184 -0
  23. toons-0.5.0/tests/integration/fixtures/decode/numbers.json +175 -0
  24. toons-0.5.0/tests/integration/fixtures/decode/objects.json +238 -0
  25. toons-0.5.0/tests/integration/fixtures/decode/path-expansion.json +173 -0
  26. toons-0.5.0/tests/integration/fixtures/decode/primitives.json +158 -0
  27. toons-0.5.0/tests/integration/fixtures/decode/root-form.json +17 -0
  28. toons-0.5.0/tests/integration/fixtures/decode/validation-errors.json +83 -0
  29. toons-0.5.0/tests/integration/fixtures/decode/whitespace.json +61 -0
  30. toons-0.5.0/tests/integration/fixtures/encode/arrays-nested.json +105 -0
  31. toons-0.5.0/tests/integration/fixtures/encode/arrays-objects.json +158 -0
  32. toons-0.5.0/tests/integration/fixtures/encode/arrays-primitive.json +87 -0
  33. toons-0.5.0/tests/integration/fixtures/encode/arrays-tabular.json +62 -0
  34. toons-0.5.0/tests/integration/fixtures/encode/delimiters.json +253 -0
  35. toons-0.5.0/tests/integration/fixtures/encode/key-folding.json +218 -0
  36. toons-0.5.0/tests/integration/fixtures/encode/objects.json +220 -0
  37. toons-0.5.0/tests/integration/fixtures/encode/primitives.json +251 -0
  38. toons-0.5.0/tests/integration/fixtures/encode/whitespace.json +44 -0
  39. toons-0.5.0/tests/integration/test_spec_fixtures.py +145 -0
  40. {toons-0.4.0 → toons-0.5.0}/tests/unit/README.md +1 -1
  41. toons-0.5.0/tests/unit/test_delimiter.py +227 -0
  42. {toons-0.4.0 → toons-0.5.0}/tests/unit/test_dumps.py +2 -2
  43. {toons-0.4.0 → toons-0.5.0}/tests/unit/test_indent.py +1 -1
  44. {toons-0.4.0 → toons-0.5.0}/tests/unit/test_spec_compliance.py +15 -5
  45. toons-0.4.0/src/toon.rs +0 -1532
  46. {toons-0.4.0 → toons-0.5.0}/.gitignore +0 -0
  47. {toons-0.4.0 → toons-0.5.0}/.pre-commit-config.yaml +0 -0
  48. {toons-0.4.0 → toons-0.5.0}/.readthedocs.yaml +0 -0
  49. {toons-0.4.0 → toons-0.5.0}/LICENSE +0 -0
  50. {toons-0.4.0 → toons-0.5.0}/docs/contributing.md +0 -0
  51. {toons-0.4.0 → toons-0.5.0}/docs/data-types.md +0 -0
  52. {toons-0.4.0 → toons-0.5.0}/docs/development.md +0 -0
  53. {toons-0.4.0 → toons-0.5.0}/docs/getting-started.md +0 -0
  54. {toons-0.4.0 → toons-0.5.0}/docs/specification.md +0 -0
  55. {toons-0.4.0 → toons-0.5.0}/examples/data.toon +0 -0
  56. {toons-0.4.0 → toons-0.5.0}/examples/file_example.py +0 -0
  57. {toons-0.4.0 → toons-0.5.0}/examples/string_example.py +0 -0
  58. {toons-0.4.0 → toons-0.5.0}/mkdocs.yml +0 -0
  59. {toons-0.4.0 → toons-0.5.0}/pyproject.toml +0 -0
  60. {toons-0.4.0 → toons-0.5.0}/requirements-dev.txt +0 -0
  61. {toons-0.4.0 → toons-0.5.0}/tests/README.md +0 -0
  62. {toons-0.4.0 → toons-0.5.0}/tests/conftest.py +0 -0
  63. {toons-0.4.0 → toons-0.5.0}/tests/data/complex_test.json +0 -0
  64. {toons-0.4.0 → toons-0.5.0}/tests/data/complex_test.toon +0 -0
  65. {toons-0.4.0 → toons-0.5.0}/tests/unit/test_complex_regression.py +0 -0
  66. {toons-0.4.0 → toons-0.5.0}/tests/unit/test_strict_flag.py +0 -0
@@ -24,17 +24,17 @@ jobs:
24
24
  strategy:
25
25
  matrix:
26
26
  platform:
27
- - runner: ubuntu-22.04
27
+ - runner: ubuntu-latest
28
28
  target: x86_64
29
- - runner: ubuntu-22.04
29
+ - runner: ubuntu-latest
30
30
  target: x86
31
- - runner: ubuntu-22.04
31
+ - runner: ubuntu-latest
32
32
  target: aarch64
33
- - runner: ubuntu-22.04
33
+ - runner: ubuntu-latest
34
34
  target: armv7
35
- - runner: ubuntu-22.04
35
+ - runner: ubuntu-latest
36
36
  target: s390x
37
- - runner: ubuntu-22.04
37
+ - runner: ubuntu-latest
38
38
  target: ppc64le
39
39
  steps:
40
40
  - uses: actions/checkout@v4
@@ -66,13 +66,13 @@ jobs:
66
66
  strategy:
67
67
  matrix:
68
68
  platform:
69
- - runner: ubuntu-22.04
69
+ - runner: ubuntu-latest
70
70
  target: x86_64
71
- - runner: ubuntu-22.04
71
+ - runner: ubuntu-latest
72
72
  target: x86
73
- - runner: ubuntu-22.04
73
+ - runner: ubuntu-latest
74
74
  target: aarch64
75
- - runner: ubuntu-22.04
75
+ - runner: ubuntu-latest
76
76
  target: armv7
77
77
  steps:
78
78
  - uses: actions/checkout@v4
@@ -2,41 +2,17 @@
2
2
  # It is not intended for manual editing.
3
3
  version = 4
4
4
 
5
- [[package]]
6
- name = "autocfg"
7
- version = "1.5.0"
8
- source = "registry+https://github.com/rust-lang/crates.io-index"
9
- checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
10
-
11
5
  [[package]]
12
6
  name = "heck"
13
7
  version = "0.5.0"
14
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
15
9
  checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
16
10
 
17
- [[package]]
18
- name = "indoc"
19
- version = "2.0.7"
20
- source = "registry+https://github.com/rust-lang/crates.io-index"
21
- checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
22
- dependencies = [
23
- "rustversion",
24
- ]
25
-
26
11
  [[package]]
27
12
  name = "libc"
28
- version = "0.2.178"
13
+ version = "0.2.180"
29
14
  source = "registry+https://github.com/rust-lang/crates.io-index"
30
- checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
31
-
32
- [[package]]
33
- name = "memoffset"
34
- version = "0.9.1"
35
- source = "registry+https://github.com/rust-lang/crates.io-index"
36
- checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
37
- dependencies = [
38
- "autocfg",
39
- ]
15
+ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
40
16
 
41
17
  [[package]]
42
18
  name = "once_cell"
@@ -46,50 +22,47 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
46
22
 
47
23
  [[package]]
48
24
  name = "portable-atomic"
49
- version = "1.13.0"
25
+ version = "1.13.1"
50
26
  source = "registry+https://github.com/rust-lang/crates.io-index"
51
- checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
27
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
52
28
 
53
29
  [[package]]
54
30
  name = "proc-macro2"
55
- version = "1.0.104"
31
+ version = "1.0.106"
56
32
  source = "registry+https://github.com/rust-lang/crates.io-index"
57
- checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
33
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
58
34
  dependencies = [
59
35
  "unicode-ident",
60
36
  ]
61
37
 
62
38
  [[package]]
63
39
  name = "pyo3"
64
- version = "0.27.2"
40
+ version = "0.28.0"
65
41
  source = "registry+https://github.com/rust-lang/crates.io-index"
66
- checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
42
+ checksum = "fcf3ccafdf54c050be48a3a086d372f77ba6615f5057211607cd30e5ac5cec6d"
67
43
  dependencies = [
68
- "indoc",
69
44
  "libc",
70
- "memoffset",
71
45
  "once_cell",
72
46
  "portable-atomic",
73
47
  "pyo3-build-config",
74
48
  "pyo3-ffi",
75
49
  "pyo3-macros",
76
- "unindent",
77
50
  ]
78
51
 
79
52
  [[package]]
80
53
  name = "pyo3-build-config"
81
- version = "0.27.2"
54
+ version = "0.28.0"
82
55
  source = "registry+https://github.com/rust-lang/crates.io-index"
83
- checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
56
+ checksum = "972720a441c91fd9c49f212a1d2d74c6e3803b231ebc8d66c51efbd7ccab11c8"
84
57
  dependencies = [
85
58
  "target-lexicon",
86
59
  ]
87
60
 
88
61
  [[package]]
89
62
  name = "pyo3-ffi"
90
- version = "0.27.2"
63
+ version = "0.28.0"
91
64
  source = "registry+https://github.com/rust-lang/crates.io-index"
92
- checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
65
+ checksum = "5994456d9dab8934d600d3867571b6410f24fbd6002570ad56356733eb54859b"
93
66
  dependencies = [
94
67
  "libc",
95
68
  "pyo3-build-config",
@@ -97,9 +70,9 @@ dependencies = [
97
70
 
98
71
  [[package]]
99
72
  name = "pyo3-macros"
100
- version = "0.27.2"
73
+ version = "0.28.0"
101
74
  source = "registry+https://github.com/rust-lang/crates.io-index"
102
- checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
75
+ checksum = "11ce9cc8d81b3c4969748807604d92b4eef363c5bb82b1a1bdb34ec6f1093a18"
103
76
  dependencies = [
104
77
  "proc-macro2",
105
78
  "pyo3-macros-backend",
@@ -109,9 +82,9 @@ dependencies = [
109
82
 
110
83
  [[package]]
111
84
  name = "pyo3-macros-backend"
112
- version = "0.27.2"
85
+ version = "0.28.0"
113
86
  source = "registry+https://github.com/rust-lang/crates.io-index"
114
- checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
87
+ checksum = "eaf4b60036a154d23282679b658e3cc7d88d3b8c9a40b43824785f232d2e1b98"
115
88
  dependencies = [
116
89
  "heck",
117
90
  "proc-macro2",
@@ -122,24 +95,18 @@ dependencies = [
122
95
 
123
96
  [[package]]
124
97
  name = "quote"
125
- version = "1.0.42"
98
+ version = "1.0.44"
126
99
  source = "registry+https://github.com/rust-lang/crates.io-index"
127
- checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
100
+ checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
128
101
  dependencies = [
129
102
  "proc-macro2",
130
103
  ]
131
104
 
132
- [[package]]
133
- name = "rustversion"
134
- version = "1.0.22"
135
- source = "registry+https://github.com/rust-lang/crates.io-index"
136
- checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
137
-
138
105
  [[package]]
139
106
  name = "syn"
140
- version = "2.0.112"
107
+ version = "2.0.114"
141
108
  source = "registry+https://github.com/rust-lang/crates.io-index"
142
- checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4"
109
+ checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
143
110
  dependencies = [
144
111
  "proc-macro2",
145
112
  "quote",
@@ -154,7 +121,7 @@ checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba"
154
121
 
155
122
  [[package]]
156
123
  name = "toons"
157
- version = "0.4.0"
124
+ version = "0.5.0"
158
125
  dependencies = [
159
126
  "pyo3",
160
127
  ]
@@ -164,9 +131,3 @@ name = "unicode-ident"
164
131
  version = "1.0.22"
165
132
  source = "registry+https://github.com/rust-lang/crates.io-index"
166
133
  checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
167
-
168
- [[package]]
169
- name = "unindent"
170
- version = "0.2.4"
171
- source = "registry+https://github.com/rust-lang/crates.io-index"
172
- checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "toons"
3
- version = "0.4.0"
3
+ version = "0.5.0"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: toons
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -24,6 +24,17 @@ Project-URL: Source, https://github.com/alesanfra/toons
24
24
 
25
25
  TOONS - Token Oriented Object Notation Serializer - is a fast Rust-based library that provides a Python interface mirroring the `json` module API, making it easy to work with the TOON format—a token-efficient data serialization format designed specifically for Large Language Models.
26
26
 
27
+
28
+ ## Documentation
29
+
30
+ 📖 Read the full documentation at **[toons.readthedocs.io](https://toons.readthedocs.io/en/stable/)**.
31
+
32
+ Quick start pages:
33
+ - 🚀 **[Getting Started](https://toons.readthedocs.io/en/stable/getting-started/)** - Installation and first steps
34
+ - 💡 **[Examples](https://toons.readthedocs.io/en/stable/examples/)** - Practical usage examples
35
+ - 📚 **[API Reference](https://toons.readthedocs.io/en/stable/api-reference/)** - Complete API documentation
36
+
37
+
27
38
  ## Why TOON?
28
39
 
29
40
  The TOON format achieves **30-60% fewer tokens** than equivalent JSON, making it ideal for LLM contexts where token count impacts costs and context capacity.
@@ -50,7 +61,7 @@ users[2]{name,age}:
50
61
  - 🚀 **Fast**: Rust implementation with PyO3 bindings
51
62
  - 📊 **Token-Efficient**: 30-60% fewer tokens than JSON
52
63
  - 🔄 **Familiar API**: Drop-in replacement for `json` module
53
- - ✅ **Spec Compliant**: Full TOON Specification v2.0 support
64
+ - ✅ **Spec Compliant**: Full TOON Specification v3.0 support
54
65
  - 🐍 **Python Native**: Works with standard Python types
55
66
 
56
67
  ## Quick Start
@@ -97,15 +108,6 @@ with open("data.toon", "r") as f:
97
108
  data = toons.load(f)
98
109
  ```
99
110
 
100
- ## Documentation
101
-
102
- 📖 **[Read the full documentation at toons.readthedocs.io](https://toons.readthedocs.io/en/stable/)**
103
-
104
- - 🚀 **[Getting Started](https://toons.readthedocs.io/en/stable/getting-started/)** - Installation and first steps
105
- - 💡 **[Examples](https://toons.readthedocs.io/en/stable/examples/)** - Practical usage examples
106
- - 📚 **[API Reference](https://toons.readthedocs.io/en/stable/api-reference/)** - Complete API documentation
107
- - 📋 **[TOON Specification](https://toons.readthedocs.io/en/stable/specification/)** - Format specification v2.0
108
-
109
111
  ## Development
110
112
 
111
113
  ```bash
@@ -10,6 +10,17 @@
10
10
 
11
11
  TOONS - Token Oriented Object Notation Serializer - is a fast Rust-based library that provides a Python interface mirroring the `json` module API, making it easy to work with the TOON format—a token-efficient data serialization format designed specifically for Large Language Models.
12
12
 
13
+
14
+ ## Documentation
15
+
16
+ 📖 Read the full documentation at **[toons.readthedocs.io](https://toons.readthedocs.io/en/stable/)**.
17
+
18
+ Quick start pages:
19
+ - 🚀 **[Getting Started](https://toons.readthedocs.io/en/stable/getting-started/)** - Installation and first steps
20
+ - 💡 **[Examples](https://toons.readthedocs.io/en/stable/examples/)** - Practical usage examples
21
+ - 📚 **[API Reference](https://toons.readthedocs.io/en/stable/api-reference/)** - Complete API documentation
22
+
23
+
13
24
  ## Why TOON?
14
25
 
15
26
  The TOON format achieves **30-60% fewer tokens** than equivalent JSON, making it ideal for LLM contexts where token count impacts costs and context capacity.
@@ -36,7 +47,7 @@ users[2]{name,age}:
36
47
  - 🚀 **Fast**: Rust implementation with PyO3 bindings
37
48
  - 📊 **Token-Efficient**: 30-60% fewer tokens than JSON
38
49
  - 🔄 **Familiar API**: Drop-in replacement for `json` module
39
- - ✅ **Spec Compliant**: Full TOON Specification v2.0 support
50
+ - ✅ **Spec Compliant**: Full TOON Specification v3.0 support
40
51
  - 🐍 **Python Native**: Works with standard Python types
41
52
 
42
53
  ## Quick Start
@@ -83,15 +94,6 @@ with open("data.toon", "r") as f:
83
94
  data = toons.load(f)
84
95
  ```
85
96
 
86
- ## Documentation
87
-
88
- 📖 **[Read the full documentation at toons.readthedocs.io](https://toons.readthedocs.io/en/stable/)**
89
-
90
- - 🚀 **[Getting Started](https://toons.readthedocs.io/en/stable/getting-started/)** - Installation and first steps
91
- - 💡 **[Examples](https://toons.readthedocs.io/en/stable/examples/)** - Practical usage examples
92
- - 📚 **[API Reference](https://toons.readthedocs.io/en/stable/api-reference/)** - Complete API documentation
93
- - 📋 **[TOON Specification](https://toons.readthedocs.io/en/stable/specification/)** - Format specification v2.0
94
-
95
97
  ## Development
96
98
 
97
99
  ```bash
@@ -53,7 +53,7 @@ docs/
53
53
  - **[Quick Start](quick-start.md)** - Get up and running quickly
54
54
  - **[Examples](examples.md)** - Practical usage examples
55
55
  - **[API Reference](api-reference.md)** - Complete API documentation
56
- - **[Specification](specification.md)** - TOON format specification v2.0
56
+ - **[Specification](specification.md)** - TOON format specification v3.0
57
57
  - **[Data Types](data-types.md)** - Type mapping and conversion
58
58
 
59
59
  ### Developer Documentation
@@ -22,7 +22,7 @@ def loads(s: str, *, strict: bool = True) -> Any
22
22
  **Parameters:**
23
23
 
24
24
  - `s` (`str`): TOON-formatted string to parse
25
- - `strict` (`bool`, optional): If `True` (default), enforce strict TOON v2.0 compliance. If `False`, allow some leniency (e.g., blank lines in arrays, indentation mismatches).
25
+ - `strict` (`bool`, optional): If `True` (default), enforce strict TOON v3.0 compliance. If `False`, allow some leniency (e.g., blank lines in arrays, indentation mismatches).
26
26
 
27
27
  **Returns:**
28
28
 
@@ -89,7 +89,7 @@ def load(fp: IO[str], *, strict: bool = True) -> Any
89
89
  **Parameters:**
90
90
 
91
91
  - `fp`: File-like object supporting `.read()` method
92
- - `strict` (`bool`, optional): If `True` (default), enforce strict TOON v2.0 compliance. If `False`, allow some leniency.
92
+ - `strict` (`bool`, optional): If `True` (default), enforce strict TOON v3.0 compliance. If `False`, allow some leniency.
93
93
 
94
94
  **Returns:**
95
95
 
@@ -122,18 +122,23 @@ except ValueError as e:
122
122
 
123
123
  ---
124
124
 
125
- ### `dumps(obj)`
125
+ ### `dumps(obj, *, indent=2, delimiter=",")`
126
126
 
127
127
  Serialize a Python object to a TOON-formatted string.
128
128
 
129
129
  **Signature:**
130
130
  ```python
131
- def dumps(obj: Any) -> str
131
+ def dumps(obj: Any, *, indent: int = 2, delimiter: str = ",") -> str
132
132
  ```
133
133
 
134
134
  **Parameters:**
135
135
 
136
136
  - `obj`: Python object to serialize (must be JSON-serializable types)
137
+ - `indent` (`int`, optional): Number of spaces per indentation level (default: 2, minimum: 2)
138
+ - `delimiter` (`str`, optional): Delimiter character for arrays and tabular format (default: ","). Supported values:
139
+ - `","` - Comma (default)
140
+ - `"\t"` - Tab
141
+ - `"|"` - Pipe
137
142
 
138
143
  **Returns:**
139
144
 
@@ -183,35 +188,50 @@ print(toons.dumps(data))
183
188
  # Alice,30
184
189
  # Bob,25
185
190
 
186
- # Nested objects
191
+ # Custom indentation (4 spaces)
192
+ data = {"nested": {"value": 42}}
193
+ print(toons.dumps(data, indent=4))
194
+ # nested:
195
+ # value: 42
196
+
197
+ # Tab delimiter
198
+ data = {"items": [1, 2, 3]}
199
+ print(toons.dumps(data, delimiter="\t"))
200
+ # items[3\t]: 1\t2\t3
201
+
202
+ # Pipe delimiter with tabular format
187
203
  data = {
188
- "user": {
189
- "name": "Alice",
190
- "contact": {"email": "alice@example.com"}
191
- }
204
+ "users": [
205
+ {"name": "Alice", "age": 30},
206
+ {"name": "Bob", "age": 25}
207
+ ]
192
208
  }
193
- print(toons.dumps(data))
194
- # user:
195
- # name: Alice
196
- # contact:
197
- # email: alice@example.com
209
+ print(toons.dumps(data, delimiter="|"))
210
+ # users[2|]{name|age}:
211
+ # Alice|30
212
+ # Bob|25
198
213
  ```
199
214
 
200
215
  ---
201
216
 
202
- ### `dump(obj, fp)`
217
+ ### `dump(obj, fp, *, indent=2, delimiter=",")`
203
218
 
204
219
  Serialize a Python object to TOON format and write to a file object.
205
220
 
206
221
  **Signature:**
207
222
  ```python
208
- def dump(obj: Any, fp: IO[str]) -> None
223
+ def dump(obj: Any, fp: IO[str], *, indent: int = 2, delimiter: str = ",") -> None
209
224
  ```
210
225
 
211
226
  **Parameters:**
212
227
 
213
228
  - `obj`: Python object to serialize
214
229
  - `fp`: File-like object supporting `.write()` method
230
+ - `indent` (`int`, optional): Number of spaces per indentation level (default: 2, minimum: 2)
231
+ - `delimiter` (`str`, optional): Delimiter character for arrays and tabular format (default: ","). Supported values:
232
+ - `","` - Comma (default)
233
+ - `"\t"` - Tab
234
+ - `"|"` - Pipe
215
235
 
216
236
  **Returns:**
217
237
 
@@ -238,6 +258,18 @@ data = {
238
258
  with open("users.toon", "w") as f:
239
259
  toons.dump(data, f)
240
260
 
261
+ # Custom indentation
262
+ with open("users.toon", "w") as f:
263
+ toons.dump(data, f, indent=4)
264
+
265
+ # Tab delimiter
266
+ with open("users.toon", "w") as f:
267
+ toons.dump(data, f, delimiter="\t")
268
+
269
+ # Pipe delimiter with custom indentation
270
+ with open("users.toon", "w") as f:
271
+ toons.dump(data, f, indent=4, delimiter="|")
272
+
241
273
  # With error handling
242
274
  try:
243
275
  with open("output.toon", "w") as f:
@@ -366,7 +366,7 @@ print(result) # None (with error message)
366
366
 
367
367
  ### Strict Mode
368
368
 
369
- By default, TOONS enforces strict compliance with the v2.0 specification. You can disable this for lenient parsing of slightly malformed data (e.g., blank lines in arrays).
369
+ By default, TOONS enforces strict compliance with the v3.0 specification. You can disable this for lenient parsing of slightly malformed data (e.g., blank lines in arrays).
370
370
 
371
371
  ```python
372
372
  import toons
@@ -9,7 +9,7 @@ TOONS provides a Python interface that mirrors the API of Python's standard `jso
9
9
  - **🚀 Fast**: Implemented in Rust with PyO3 bindings for maximum performance
10
10
  - **📊 Token-Efficient**: 30-60% fewer tokens than JSON, ideal for LLM contexts
11
11
  - **🔄 Familiar API**: Mirrors Python's `json` module (`load`, `loads`, `dump`, `dumps`)
12
- - **✅ Spec Compliant**: Full support for TOON Specification v2.0
12
+ - **✅ Spec Compliant**: Full support for TOON Specification v3.0
13
13
  - **🐍 Python Native**: Returns/accepts Python dict, list, str, int, float, bool, None
14
14
  - **📁 File & String**: Complete support for both file I/O and string operations
15
15
 
@@ -64,7 +64,7 @@ The library is fully implemented in Rust with a custom parser and serializer, us
64
64
  - High-performance parsing and serialization
65
65
  - Memory efficiency
66
66
  - Type safety
67
- - Full TOON Specification v2.0 compliance
67
+ - Full TOON Specification v3.0 compliance
68
68
  - Complete control over implementation details
69
69
 
70
70
  ## Next Steps
@@ -219,11 +219,11 @@ class TestRoundTrip:
219
219
 
220
220
  ### Specification Compliance Tests
221
221
 
222
- Verify TOON Spec v2.0 compliance:
222
+ Verify TOON Spec v3.0 compliance:
223
223
 
224
224
  ```python
225
225
  class TestSpecCompliance:
226
- """Test TOON Specification v2.0 compliance."""
226
+ """Test TOON Specification v3.0 compliance."""
227
227
 
228
228
  def test_array_count_notation(self):
229
229
  """Test that arrays include element count [N]."""
@@ -7,8 +7,8 @@
7
7
  //!
8
8
  //! # Features
9
9
  //!
10
- //! - **Full TOON v2.0 Specification Compliance**: Implements all features
11
- //! from the official TOON specification dated 2025-11-10
10
+ //! - **Full TOON v3.0 Specification Compliance**: Implements all features
11
+ //! from the official TOON specification dated 2025-11-24
12
12
  //! - **Direct Python Integration**: No intermediate JSON representation
13
13
  //! - **Configurable Indentation**: Support for custom indent sizes (≥2 spaces)
14
14
  //! - **Smart Parser**: Automatic indentation detection when parsing
@@ -54,7 +54,7 @@
54
54
  //!
55
55
  //! # Specification
56
56
  //!
57
- //! This implementation follows TOON Specification v2.0 (2025-11-10).
57
+ //! This implementation follows TOON Specification v3.0 (2025-11-24).
58
58
  //! For complete specification details, see:
59
59
  //! <https://github.com/johannschopplich/toon>
60
60
 
@@ -69,7 +69,7 @@ mod toon;
69
69
  ///
70
70
  /// Args:
71
71
  /// s: A string containing TOON formatted data
72
- /// strict: If True (default), enforce strict TOON v2.0 compliance.
72
+ /// strict: If True (default), enforce strict TOON v3.0 compliance.
73
73
  /// If False, allow some leniency (e.g. blank lines in arrays).
74
74
  ///
75
75
  /// Returns:
@@ -84,9 +84,16 @@ mod toon;
84
84
  /// >>> print(data)
85
85
  /// {'name': 'Alice', 'age': 30}
86
86
  #[pyfunction]
87
- #[pyo3(signature = (s, *, strict=true))]
88
- fn loads(py: Python, s: String, strict: bool) -> PyResult<Py<PyAny>> {
89
- toon::deserialize(py, &s, strict)
87
+ #[pyo3(signature = (s, *, strict=true, expand_paths=None, indent=None))]
88
+ fn loads(
89
+ py: Python,
90
+ s: String,
91
+ strict: bool,
92
+ expand_paths: Option<&str>,
93
+ indent: Option<usize>,
94
+ ) -> PyResult<Py<PyAny>> {
95
+ let expand_mode = expand_paths.unwrap_or("off");
96
+ toon::deserialize(py, &s, strict, expand_mode, indent)
90
97
  }
91
98
 
92
99
  /// Deserialize a TOON formatted file to a Python object.
@@ -96,7 +103,7 @@ fn loads(py: Python, s: String, strict: bool) -> PyResult<Py<PyAny>> {
96
103
  ///
97
104
  /// Args:
98
105
  /// fp: A file-like object with a read() method returning a string
99
- /// strict: If True (default), enforce strict TOON v2.0 compliance.
106
+ /// strict: If True (default), enforce strict TOON v3.0 compliance.
100
107
  /// If False, allow some leniency (e.g. blank lines in arrays).
101
108
  ///
102
109
  /// Returns:
@@ -110,12 +117,19 @@ fn loads(py: Python, s: String, strict: bool) -> PyResult<Py<PyAny>> {
110
117
  /// >>> with open('data.toon', 'r') as f:
111
118
  /// ... data = toons.load(f)
112
119
  #[pyfunction]
113
- #[pyo3(signature = (fp, *, strict=true))]
114
- fn load(py: Python, fp: &Bound<'_, PyAny>, strict: bool) -> PyResult<Py<PyAny>> {
120
+ #[pyo3(signature = (fp, *, strict=true, expand_paths=None, indent=None))]
121
+ fn load(
122
+ py: Python,
123
+ fp: &Bound<'_, PyAny>,
124
+ strict: bool,
125
+ expand_paths: Option<&str>,
126
+ indent: Option<usize>,
127
+ ) -> PyResult<Py<PyAny>> {
128
+ let expand_mode = expand_paths.unwrap_or("off");
115
129
  let read_method = fp.getattr("read")?;
116
130
  let content = read_method.call0()?;
117
131
  let content_str: String = content.extract()?;
118
- toon::deserialize(py, &content_str, strict)
132
+ toon::deserialize(py, &content_str, strict, expand_mode, indent)
119
133
  }
120
134
 
121
135
  /// Serialize a Python object to a TOON formatted string.
@@ -144,9 +158,30 @@ fn load(py: Python, fp: &Bound<'_, PyAny>, strict: bool) -> PyResult<Py<PyAny>>
144
158
  /// >>> # Custom indentation
145
159
  /// >>> toon_str = toons.dumps(data, indent=4)
146
160
  #[pyfunction]
147
- #[pyo3(signature = (obj, *, indent=2))]
148
- fn dumps(py: Python, obj: &Bound<'_, PyAny>, indent: usize) -> PyResult<String> {
149
- toon::serialize(py, obj, indent)
161
+ #[pyo3(signature = (obj, *, indent=2, delimiter=",", key_folding=None, flatten_depth=None))]
162
+ fn dumps(
163
+ py: Python,
164
+ obj: &Bound<'_, PyAny>,
165
+ indent: usize,
166
+ delimiter: &str,
167
+ key_folding: Option<&str>,
168
+ flatten_depth: Option<usize>,
169
+ ) -> PyResult<String> {
170
+ if indent < 2 {
171
+ return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
172
+ "indent must be >= 2",
173
+ ));
174
+ }
175
+ // key_folding: only enable when explicitly set to "safe", "on", or "always"
176
+ let enable_key_folding = matches!(key_folding, Some("safe") | Some("on") | Some("always"));
177
+ toon::serialize(
178
+ py,
179
+ obj,
180
+ delimiter.chars().next().unwrap(),
181
+ indent,
182
+ enable_key_folding,
183
+ flatten_depth,
184
+ )
150
185
  }
151
186
 
152
187
  /// Serialize a Python object to a TOON formatted file.
@@ -171,9 +206,31 @@ fn dumps(py: Python, obj: &Bound<'_, PyAny>, indent: usize) -> PyResult<String>
171
206
  /// >>> with open('data.toon', 'w') as f:
172
207
  /// ... toons.dump(data, f, indent=4)
173
208
  #[pyfunction]
174
- #[pyo3(signature = (obj, fp, *, indent=2))]
175
- fn dump(py: Python, obj: &Bound<'_, PyAny>, fp: &Bound<'_, PyAny>, indent: usize) -> PyResult<()> {
176
- let toon_str = toon::serialize(py, obj, indent)?;
209
+ #[pyo3(signature = (obj, fp, *, indent=2, delimiter=",", key_folding=None, flatten_depth=None))]
210
+ fn dump(
211
+ py: Python,
212
+ obj: &Bound<'_, PyAny>,
213
+ fp: &Bound<'_, PyAny>,
214
+ indent: usize,
215
+ delimiter: &str,
216
+ key_folding: Option<&str>,
217
+ flatten_depth: Option<usize>,
218
+ ) -> PyResult<()> {
219
+ if indent < 2 {
220
+ return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
221
+ "indent must be >= 2",
222
+ ));
223
+ }
224
+ // key_folding: only enable when explicitly set to "safe", "on", or "always"
225
+ let enable_key_folding = matches!(key_folding, Some("safe") | Some("on") | Some("always"));
226
+ let toon_str = toon::serialize(
227
+ py,
228
+ obj,
229
+ delimiter.chars().next().unwrap(),
230
+ indent,
231
+ enable_key_folding,
232
+ flatten_depth,
233
+ )?;
177
234
  let write_method = fp.getattr("write")?;
178
235
  write_method.call1((toon_str,))?;
179
236
  Ok(())
@@ -197,7 +254,7 @@ implementation with Python bindings for high-performance encoding
197
254
  and decoding of TOON data.
198
255
 
199
256
  Features:
200
- - Full TOON v2.0 Specification Compliance
257
+ - Full TOON v3.0 Specification Compliance
201
258
  - Direct Python Integration (no JSON overhead)
202
259
  - Configurable Indentation (≥2 spaces)
203
260
  - Smart Parser with automatic indentation detection
@@ -214,7 +271,7 @@ Quick Start:
214
271
  >>> data = toons.loads(toon_str)
215
272
 
216
273
  Specification:
217
- TOON Specification v2.0 (2025-11-10)
274
+ TOON Specification v3.0 (2025-11-24)
218
275
  https://github.com/johannschopplich/toon
219
276
  ",
220
277
  )?;