json2xml 6.1.0__tar.gz → 6.2.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 (49) hide show
  1. {json2xml-6.1.0 → json2xml-6.2.0}/HISTORY.rst +11 -0
  2. {json2xml-6.1.0 → json2xml-6.2.0}/PKG-INFO +4 -3
  3. json2xml-6.2.0/docs/benchmarks.rst +203 -0
  4. json2xml-6.2.0/docs/rust_memory_benchmark.rst +110 -0
  5. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/__init__.py +1 -1
  6. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/dicttoxml.py +150 -40
  7. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/dicttoxml_fast.py +10 -9
  8. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/json2xml.py +6 -4
  9. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/utils.py +19 -5
  10. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml.egg-info/PKG-INFO +4 -3
  11. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml.egg-info/SOURCES.txt +2 -0
  12. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml.egg-info/requires.txt +3 -2
  13. {json2xml-6.1.0 → json2xml-6.2.0}/pyproject.toml +4 -3
  14. {json2xml-6.1.0 → json2xml-6.2.0}/requirements.in +1 -1
  15. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_dict2xml.py +78 -0
  16. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_dicttoxml_fast_fallback.py +42 -3
  17. json2xml-6.2.0/tests/test_dicttoxml_unit.py +163 -0
  18. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_json2xml.py +27 -0
  19. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_rust_dicttoxml.py +4 -4
  20. json2xml-6.1.0/docs/benchmarks.rst +0 -221
  21. {json2xml-6.1.0 → json2xml-6.2.0}/AUTHORS.rst +0 -0
  22. {json2xml-6.1.0 → json2xml-6.2.0}/CONTRIBUTING.rst +0 -0
  23. {json2xml-6.1.0 → json2xml-6.2.0}/LICENSE +0 -0
  24. {json2xml-6.1.0 → json2xml-6.2.0}/MANIFEST.in +0 -0
  25. {json2xml-6.1.0 → json2xml-6.2.0}/README.rst +0 -0
  26. {json2xml-6.1.0 → json2xml-6.2.0}/docs/Makefile +0 -0
  27. {json2xml-6.1.0 → json2xml-6.2.0}/docs/authors.rst +0 -0
  28. {json2xml-6.1.0 → json2xml-6.2.0}/docs/conf.py +0 -0
  29. {json2xml-6.1.0 → json2xml-6.2.0}/docs/contributing.rst +0 -0
  30. {json2xml-6.1.0 → json2xml-6.2.0}/docs/history.rst +0 -0
  31. {json2xml-6.1.0 → json2xml-6.2.0}/docs/index.rst +0 -0
  32. {json2xml-6.1.0 → json2xml-6.2.0}/docs/installation.rst +0 -0
  33. {json2xml-6.1.0 → json2xml-6.2.0}/docs/json2xml.rst +0 -0
  34. {json2xml-6.1.0 → json2xml-6.2.0}/docs/make.bat +0 -0
  35. {json2xml-6.1.0 → json2xml-6.2.0}/docs/modules.rst +0 -0
  36. {json2xml-6.1.0 → json2xml-6.2.0}/docs/readme.rst +0 -0
  37. {json2xml-6.1.0 → json2xml-6.2.0}/docs/usage.rst +0 -0
  38. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/cli.py +0 -0
  39. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml/types.py +0 -0
  40. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml.egg-info/dependency_links.txt +0 -0
  41. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml.egg-info/entry_points.txt +0 -0
  42. {json2xml-6.1.0 → json2xml-6.2.0}/json2xml.egg-info/top_level.txt +0 -0
  43. {json2xml-6.1.0 → json2xml-6.2.0}/setup.cfg +0 -0
  44. {json2xml-6.1.0 → json2xml-6.2.0}/setup.py +0 -0
  45. {json2xml-6.1.0 → json2xml-6.2.0}/tests/__init__.py +0 -0
  46. {json2xml-6.1.0 → json2xml-6.2.0}/tests/conftest.py +0 -0
  47. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_cli.py +0 -0
  48. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_missing_coverage.py +0 -0
  49. {json2xml-6.1.0 → json2xml-6.2.0}/tests/test_utils.py +0 -0
@@ -1,4 +1,15 @@
1
1
 
2
+ 6.2.0 / 2026-06-05
3
+ ==================
4
+
5
+ * feat: reduce peak serializer memory in the pure Python rooted-output path
6
+ * feat: reduce Rust extension peak serializer memory by writing directly into Python bytes
7
+ * fix: split PyO3 extension-module linking so ``cargo test`` works on macOS
8
+ * chore: release ``json2xml-rs`` 0.3.0 and make ``json2xml[fast]`` require the memory-saving Rust package
9
+ * chore: update the Rust extension crate to Rust 2024 with rust-version 1.96
10
+ * docs: add reproducible Rust memory benchmark results showing about 49% lower serializer RSS delta
11
+
12
+
2
13
  6.1.0 / 2026-05-04
3
14
  ==================
4
15
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: json2xml
3
- Version: 6.1.0
3
+ Version: 6.2.0
4
4
  Summary: Simple Python Library to convert JSON to XML
5
5
  Author-email: Vinit Kumar <mail@vinitkumar.me>
6
6
  License: Apache Software License 2.0
@@ -23,15 +23,16 @@ Description-Content-Type: text/x-rst
23
23
  License-File: LICENSE
24
24
  License-File: AUTHORS.rst
25
25
  Requires-Dist: defusedxml
26
- Requires-Dist: urllib3
26
+ Requires-Dist: urllib3>=2.7.0
27
27
  Provides-Extra: dev
28
28
  Requires-Dist: pytest>=8.4.1; extra == "dev"
29
29
  Requires-Dist: pytest-cov; extra == "dev"
30
30
  Requires-Dist: coverage; extra == "dev"
31
31
  Requires-Dist: setuptools; extra == "dev"
32
+ Requires-Dist: pygments>=2.20.0; extra == "dev"
32
33
  Requires-Dist: xmltodict>=0.12.0; extra == "dev"
33
34
  Provides-Extra: fast
34
- Requires-Dist: json2xml-rs>=0.1.0; extra == "fast"
35
+ Requires-Dist: json2xml-rs>=0.3.0; extra == "fast"
35
36
  Dynamic: license-file
36
37
 
37
38
  .. image:: ./json2xml-hero.png
@@ -0,0 +1,203 @@
1
+ Benchmarks
2
+ ==========
3
+
4
+ Comprehensive performance comparison between all json2xml implementations.
5
+
6
+ Test Environment
7
+ ----------------
8
+
9
+ * **Machine**: Apple Silicon (arm64)
10
+ * **OS**: macOS 26.5 (Darwin 25.5.0)
11
+ * **Python**: 3.14.4
12
+ * **Date**: May 27, 2026
13
+ * **CLI tools**: ``json2xml-go`` and ``json2xml-zig`` from ``/Users/vinitkumar/.local/bin``
14
+
15
+ Implementations Tested
16
+ ~~~~~~~~~~~~~~~~~~~~~~
17
+
18
+ .. list-table::
19
+ :header-rows: 1
20
+ :widths: 25 20 55
21
+
22
+ * - Implementation
23
+ - Type
24
+ - Notes
25
+ * - Python
26
+ - Library
27
+ - Pure Python ``json2xml``
28
+ * - Rust
29
+ - Library
30
+ - Native extension via PyO3, imported as ``json2xml_rs``
31
+ * - Go
32
+ - CLI
33
+ - Standalone ``json2xml-go`` binary
34
+ * - Zig
35
+ - CLI
36
+ - Standalone ``json2xml-zig`` binary
37
+
38
+ Test Data
39
+ ~~~~~~~~~
40
+
41
+ .. list-table::
42
+ :header-rows: 1
43
+ :widths: 20 55 25
44
+
45
+ * - Size
46
+ - Description
47
+ - Bytes
48
+ * - Small
49
+ - Simple object ``{"name": "John", "age": 30, "city": "New York"}``
50
+ - 47
51
+ * - Medium
52
+ - 10 generated records with nested structures
53
+ - 3,215
54
+ * - bigexample.json
55
+ - Real-world patent data
56
+ - 2,018
57
+ * - Large
58
+ - 100 generated records with nested structures
59
+ - 32,206
60
+ * - Very Large
61
+ - 1,000 generated records with nested structures
62
+ - 323,131
63
+
64
+ Results
65
+ -------
66
+
67
+ Performance Summary
68
+ ~~~~~~~~~~~~~~~~~~~
69
+
70
+ .. list-table::
71
+ :header-rows: 1
72
+ :widths: 28 18 18 18 18
73
+
74
+ * - Test Case
75
+ - Python
76
+ - Rust
77
+ - Go
78
+ - Zig
79
+ * - Small (47B)
80
+ - 3.19µs
81
+ - 0.86µs
82
+ - 6.05ms
83
+ - 3.08ms
84
+ * - Medium (3.2KB)
85
+ - 214.83µs
86
+ - 18.41µs
87
+ - 5.85ms
88
+ - 3.12ms
89
+ * - bigexample (2KB)
90
+ - 91.20µs
91
+ - 7.32µs
92
+ - 5.76ms
93
+ - 3.08ms
94
+ * - Large (32KB)
95
+ - 2.07ms
96
+ - 175.46µs
97
+ - 5.89ms
98
+ - 3.73ms
99
+ * - Very Large (323KB)
100
+ - 21.20ms
101
+ - 1.48ms
102
+ - 6.82ms
103
+ - 7.82ms
104
+
105
+ Speedup vs Pure Python
106
+ ~~~~~~~~~~~~~~~~~~~~~~
107
+
108
+ .. list-table::
109
+ :header-rows: 1
110
+ :widths: 34 22 22 22
111
+
112
+ * - Test Case
113
+ - Rust
114
+ - Go
115
+ - Zig
116
+ * - Small (47B)
117
+ - **3.7x**
118
+ - 0.0x*
119
+ - 0.0x*
120
+ * - Medium (3.2KB)
121
+ - **11.7x**
122
+ - 0.0x*
123
+ - 0.1x*
124
+ * - bigexample (2KB)
125
+ - **12.5x**
126
+ - 0.0x*
127
+ - 0.0x*
128
+ * - Large (32KB)
129
+ - **11.8x**
130
+ - 0.4x*
131
+ - 0.6x*
132
+ * - Very Large (323KB)
133
+ - **14.4x**
134
+ - **3.1x**
135
+ - **2.7x**
136
+
137
+ *CLI tools have process spawn overhead of about 3-6ms, which dominates for small inputs.*
138
+
139
+ Key Observations
140
+ ----------------
141
+
142
+ Rust remains the best option for Python library calls. It avoids process overhead and is about 4-14x faster than the optimized pure Python path in this run.
143
+
144
+ Recent pure Python improvements substantially reduced conversion time. Medium and large inputs are roughly an order of magnitude faster than the April 2026 baseline, so relative Rust speedups are lower even though Rust is still fastest.
145
+
146
+ Go and Zig remain useful for native CLI workflows. They are slower for small and medium inputs because startup dominates, but both beat Python on the 323KB workload when full CLI process time is measured.
147
+
148
+ See ``docs/rust_memory_benchmark.rst`` for the June 2026 Rust peak-memory comparison between the previous extension-boundary copy and the Python bytes-writer implementation.
149
+
150
+ When to Use Each Implementation
151
+ -------------------------------
152
+
153
+ .. list-table::
154
+ :header-rows: 1
155
+ :widths: 40 25 35
156
+
157
+ * - Use Case
158
+ - Recommended
159
+ - Why
160
+ * - Python library calls
161
+ - **Rust**
162
+ - 4-14x faster, no process overhead
163
+ * - Small files via CLI
164
+ - **Zig**
165
+ - Fastest startup among native CLIs in this run
166
+ * - Large files via CLI
167
+ - **Go** or **Zig**
168
+ - Both are faster than Python at 323KB
169
+ * - Batch processing
170
+ - **Go** or **Rust**
171
+ - Choose based on shell vs Python integration
172
+ * - Pure Python required
173
+ - **Python**
174
+ - Always available
175
+
176
+ Running the Benchmarks
177
+ ----------------------
178
+
179
+ Run benchmarks from a clean checkout with the project installed in an isolated environment.
180
+
181
+ .. code-block:: bash
182
+
183
+ uv venv
184
+ source .venv/bin/activate
185
+ uv pip install -e .
186
+ python benchmark_all.py
187
+
188
+ For Rust benchmarks, install the extension into the same environment.
189
+
190
+ .. code-block:: bash
191
+
192
+ uv pip install maturin
193
+ cd rust
194
+ maturin develop --release
195
+ cd ..
196
+
197
+ For native CLI benchmarks, install the external tools and verify that the commands are visible.
198
+
199
+ .. code-block:: bash
200
+
201
+ go install github.com/vinitkumar/json2xml-go@latest
202
+ which json2xml-go
203
+ which json2xml-zig
@@ -0,0 +1,110 @@
1
+ Rust Memory Benchmark
2
+ =====================
3
+
4
+ This benchmark compares peak memory usage before and after the Rust serializer started writing directly into Python ``bytes``.
5
+
6
+ Summary
7
+ -------
8
+
9
+ The current branch reduces serializer peak RSS by about **77.44 MiB** on a 100,000-record payload that produces **78.17 MiB** of XML. That is a **49.1% reduction** in serializer memory delta compared with the previous PR commit.
10
+
11
+ .. list-table::
12
+ :header-rows: 1
13
+ :widths: 24 22 22 22 22
14
+
15
+ * - Version
16
+ - Commit
17
+ - Avg peak RSS
18
+ - Avg serializer delta
19
+ - Avg time
20
+ * - Previous
21
+ - ``7dd86b0``
22
+ - 349.15 MiB
23
+ - 157.70 MiB
24
+ - 0.180s
25
+ * - Current
26
+ - ``07d840f``
27
+ - 271.65 MiB
28
+ - 80.26 MiB
29
+ - 0.265s
30
+
31
+ The memory result matches the implementation change: the previous version held roughly one final XML payload in Rust plus one Python ``bytes`` payload, while the current version writes into the Python ``bytes`` object directly.
32
+
33
+ Methodology
34
+ -----------
35
+
36
+ The benchmark uses ``benchmark_memory_rust.py`` with a deterministic generated payload so the Rust fast path can be measured without file parsing or pure-Python fallback behavior.
37
+
38
+ * Machine: Apple Silicon arm64
39
+ * OS: macOS 26.5
40
+ * Python: 3.14.0
41
+ * Build: ``python3 -m maturin develop --release --offline``
42
+ * Payload: 100,000 nested records
43
+ * Input JSON size: 44.31 MiB
44
+ * Output XML size: 78.17 MiB
45
+ * Measurement: process ``ru_maxrss`` after payload creation versus peak after ``json2xml_rs.dicttoxml(payload, attr_type=True)``
46
+ * Sampling: three fresh Python processes per version
47
+
48
+ The baseline RSS is captured after the large Python payload is already built. The reported serializer delta is ``peak_rss - baseline_rss``, which focuses the comparison on output construction rather than payload allocation.
49
+
50
+ Raw Samples
51
+ -----------
52
+
53
+ .. list-table::
54
+ :header-rows: 1
55
+ :widths: 24 18 18 18 18
56
+
57
+ * - Run
58
+ - Baseline RSS
59
+ - Peak RSS
60
+ - Serializer delta
61
+ - Time
62
+ * - previous-release-1
63
+ - 191.53 MiB
64
+ - 349.22 MiB
65
+ - 157.69 MiB
66
+ - 0.182s
67
+ * - previous-release-2
68
+ - 191.39 MiB
69
+ - 349.09 MiB
70
+ - 157.70 MiB
71
+ - 0.179s
72
+ * - previous-release-3
73
+ - 191.44 MiB
74
+ - 349.14 MiB
75
+ - 157.70 MiB
76
+ - 0.178s
77
+ * - current-release-1
78
+ - 191.45 MiB
79
+ - 271.77 MiB
80
+ - 80.31 MiB
81
+ - 0.265s
82
+ * - current-release-2
83
+ - 191.48 MiB
84
+ - 271.64 MiB
85
+ - 80.16 MiB
86
+ - 0.272s
87
+ * - current-release-3
88
+ - 191.25 MiB
89
+ - 271.55 MiB
90
+ - 80.30 MiB
91
+ - 0.258s
92
+
93
+ Tradeoff
94
+ --------
95
+
96
+ The memory improvement comes with a throughput cost in this release benchmark. Average conversion time increased from 0.180s to 0.265s, about **47.5% slower** for this payload.
97
+
98
+ That cost is likely from routing every XML write through ``std::io::Write`` and PyO3's bytes writer. The memory win is substantial for large outputs, but latency-sensitive callers may want more timing data before treating the bytes-writer path as a universal improvement.
99
+
100
+ Reproduction
101
+ ------------
102
+
103
+ Run each version in a fresh process after installing the desired Rust extension build.
104
+
105
+ .. code-block:: bash
106
+
107
+ python3 -m maturin develop --release --offline
108
+ python3 benchmark_memory_rust.py --records 100000 --label current-release-1
109
+
110
+ For the previous comparison, install commit ``7dd86b0`` in a temporary worktree, then run the same command from the main checkout so the benchmark script stays identical.
@@ -2,4 +2,4 @@
2
2
 
3
3
  __author__ = """Vinit Kumar"""
4
4
  __email__ = "mail@vinitkumar.me"
5
- __version__ = "6.1.0"
5
+ __version__ = "6.2.0"