Skip to content

chore: bump pyo3#276

Merged
vinitkumar merged 11 commits intomasterfrom
fix/cargo-improvements
Mar 12, 2026
Merged

chore: bump pyo3#276
vinitkumar merged 11 commits intomasterfrom
fix/cargo-improvements

Conversation

@vinitkumar
Copy link
Owner

@vinitkumar vinitkumar commented Mar 12, 2026

Summary

  • upgrade the Rust extension to pyo3 0.28.2 and bump the Rust package version to 0.2.0
  • fix several Rust binding correctness issues so XML output matches the Python implementation more closely
  • refactor the Rust writer to reduce duplicate dispatch logic and avoid recursive intermediate string allocations
  • refresh benchmark numbers and README performance claims to reflect the latest Rust implementation

What changed

  • prevent double-escaping when invalid XML keys fall back to name="..." attributes
  • use Python str() for float rendering so values like 1.0 preserve Python-compatible formatting
  • propagate iterator errors instead of silently dropping exceptions from try_iter()
  • validate custom_root and raise ValueError for invalid XML element names
  • replace repeated conversion paths with a single buffered write flow (write_value, write_dict_contents, write_list_contents)
  • add direct buffer helpers for text escaping, attribute escaping, and CDATA emission to cut allocation overhead
  • add targeted tests for escaping and CDATA helpers
  • update README and benchmark docs with the new Rust speedups and current measurements

Validation

  • Rust code formatted and clippy/test follow-up fixes applied in this branch
  • benchmark and documentation values updated to match the current Rust extension behavior

@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.89%. Comparing base (a70b9ef) to head (0061df7).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #276   +/-   ##
=======================================
  Coverage   95.89%   95.89%           
=======================================
  Files           5        5           
  Lines         463      463           
=======================================
  Hits          444      444           
  Misses         19       19           
Flag Coverage Δ
unittests 95.89% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

vinitkumar and others added 10 commits March 12, 2026 16:43
…l_name

make_valid_xml_name was calling escape_xml(key) and storing the escaped
value. Later, make_attr_string would escape it again, producing output
like name="tag&amp;amp;name" instead of name="tag&amp;name".

Now make_valid_xml_name operates on the raw key and lets make_attr_string
handle the single escaping pass.

Amp-Thread-ID: https://ampcode.com/threads/T-019ce197-0f45-7644-a010-590c20704f18
Co-authored-by: Amp <amp@ampcode.com>
Rust's f64::to_string() renders 1.0 as "1" while Python gives "1.0".
Since this is a drop-in replacement for the Python dicttoxml, use
obj.str() to get Python's native float representation.

Amp-Thread-ID: https://ampcode.com/threads/T-019ce197-0f45-7644-a010-590c20704f18
Co-authored-by: Amp <amp@ampcode.com>
The try_iter() path used filter_map(|r| r.ok()) which silently dropped
any exceptions raised during iteration. Now uses collect::<PyResult<_>>()?
to properly propagate errors to the caller.

Amp-Thread-ID: https://ampcode.com/threads/T-019ce197-0f45-7644-a010-590c20704f18
Co-authored-by: Amp <amp@ampcode.com>
Previously custom_root was written directly into XML tags without
validation, allowing arbitrary strings to produce invalid XML output.
Now raises ValueError for invalid root element names.

Amp-Thread-ID: https://ampcode.com/threads/T-019ce197-0f45-7644-a010-590c20704f18
Co-authored-by: Amp <amp@ampcode.com>
…el escaping

Major restructuring of the Rust extension:

- Collapsed three identical type-dispatch chains (convert_value,
  convert_dict, convert_list) into a single write_value() function.
  Removes ~300 lines of duplicated if/else logic.

- All XML writing now appends to a single shared String buffer via
  write_value/write_dict_contents/write_list_contents instead of
  allocating intermediate Strings at every recursion level.

- Replaced char-by-char escape_xml with byte-scanning push_escaped_text
  (for text nodes, only escapes &<>) and push_escaped_attr (for
  attributes, also escapes quotes). Copies clean slices in bulk.

- Replaced format!-based wrap_cdata with push_cdata that writes
  directly to the buffer without intermediate allocations.

- Replaced to_lowercase().starts_with("xml") in is_valid_xml_name
  with eq_ignore_ascii_case to avoid allocating a lowercased copy.

- Removed unused std::fmt::Write import, added #[derive(Copy, Clone)]
  to ConvertConfig, gated helper functions behind cfg(python).

- Added tests for push_escaped_text, push_escaped_attr, push_cdata.

Amp-Thread-ID: https://ampcode.com/threads/T-019ce197-0f45-7644-a010-590c20704f18
Co-authored-by: Amp <amp@ampcode.com>
@vinitkumar vinitkumar merged commit ab4a750 into master Mar 12, 2026
61 checks passed
@vinitkumar vinitkumar deleted the fix/cargo-improvements branch March 12, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant