Skip to content

Docxodus v12.1.0: drop WmlComparer for DocxDiff (1.0.0) - #32

Merged
JSv4 merged 3 commits into
mainfrom
upgrade-docxodus-v12
Sep 6, 2026
Merged

Docxodus v12.1.0: drop WmlComparer for DocxDiff (1.0.0)#32
JSv4 merged 3 commits into
mainfrom
upgrade-docxodus-v12

Conversation

@JSv4

@JSv4 JSv4 commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Tracks the Docxodus submodule from v7.0.0 to v12.1.0 and releases the result as 1.0.0.

Docxodus v11.0.0 deleted the WmlComparer engine in favour of DocxDiff, its default since v8.0.0 and now mature. That removal reaches straight into this project's public API, which has exposed the upstream selector as a keyword argument since 0.3.0.

Breaking changes

Three keyword arguments are removed from DocxodusEngine.run_redline() and raise ValueError:

Argument Why it is gone
engine Selected between wmlcomparer and docxdiff. There is nothing left to select.
detail_threshold Tuned WmlComparer's LCS granularity. DocxDiff's granularity is structural.
simplify_move_markup Worked around WmlComparer's move markup. DocxDiff renders moves natively.

They raise rather than being ignored, and that is the load-bearing part of this PR. Simply deleting the code path would not have produced a breaking change — it would have produced a wrong-answer change. _build_command only reads keys it knows about, so run_redline(..., engine="wmlcomparer") would have become a silently-ignored kwarg handing the caller DocxDiff output while they believed they had selected WmlComparer.

There is a second, independent reason: the v12 CLI writes a warning to stderr for --detail-threshold= and --simplify-move-markup. run_redline surfaces any non-empty stderr, so passing them through breaks every assert stderr is None in the suite.

Unknown keyword arguments are now rejected on the same reasoning — detial_threshold=0.5 used to vanish in silence, which is indistinguishable from a setting that did nothing.

The Action's comparison input maps onto the deleted selector and now fails the run.

Bug fixes

Issue #30 — leaked NamedTemporaryFile. The output scratch file was tempfile.NamedTemporaryFile(delete=False).name, which drops the only reference to the file object. Its finalizer reports ResourceWarning on CPython 3.13+, once per call, and under -W error surfaces as an unraisable exception attributed to whatever test was running when the collector fired. Now mkstemp, which is the right tool when only a path is wanted.

Data loss on path inputs — found while fixing #30, and the most user-protective change here. run_redline appended original_path and modified_path to temp_files unconditionally, and the finally block os.removes every entry. When the caller passed a path — a documented, type-hinted input mode that docs/quickstart.md demonstrates — those entries were the caller's own files:

engine.run_redline("Author", "original.docx", "modified.docx")  # deleted both

Only byte inputs were safe, which is why the Action (bytes-only) never hit it. Only files this library creates are registered for cleanup now. Anyone who avoided the path API because it ate their documents can use it.

Revision counts: measured, not predicted

The fixture count is now 10. It is neither the 9 the old default reported nor the 11 the 0.3.0 opt-in reported — v11/v12 changed region arrangement, surplus table cells and section defaults. Measured against a freshly built v12.1.0 binary, with ~/.cache/python-redlines cleared first (the extraction cache keys on the installed binary package version, so a rebuilt binary at an unchanged version is otherwise silently ignored).

The Action self-test workflow no longer asserts an exact count: it installs python-redlines from PyPI, so its number tracks the published version, not this branch. Pinning it to 10 would fail every run until 1.0.0 ships; pinning it to 9 would fail every run after. It asserts a positive count — which is what "the action plumbing works" means — and the exact count stays pinned in tests/test_docxodus_engine.py, which runs against the working tree.

Deliberately not done

XmlPowerToolsEngine wraps the original Open-XML-PowerTools WmlComparer in a separately published wheel. Retiring a package users have pinned is its own decision with its own migration story, so it keeps shipping and keeps working — it just emits a DeprecationWarning now. Release notes say "the Docxodus engine no longer carries WmlComparer", not "Python-Redlines is WmlComparer-free", which would be false while that wheel exists. all still resolves to both engines, so existing pins do not change meaning.

Verification

  • 72 passed, 1 skipped — the skip is the ResourceWarning assertion, which only fires on CPython 3.13+ (this box is 3.12); a version-independent test asserts the same defect directly.
  • Built and ran the v12.1.0 binary on linux-x64, and confirmed --engine= now exits 1 as an unknown flag.
  • Built win-x64 as a cross-RID check — the v7→v12 jump touched 1366 files, so dotnet publish -r <rid> --self-contained needed re-verifying against something other than the native RID before the six-RID release matrix runs.

Not verifiable locally: macOS and Windows runners, and the other four RIDs. CI on this PR is the first real test of the v12 submodule on those.

Closes #30

🤖 Generated with Claude Code

https://claude.ai/code/session_014ed9PC7DDco5AFPjsZyy9F

JSv4 and others added 3 commits September 5, 2026 23:12
Docxodus v11.0.0 deleted the WmlComparer engine in favour of DocxDiff,
which has been its default since v8.0.0. That removal reaches straight
into this project's public API, which has exposed the upstream selector
as a keyword argument since 0.3.0.

BREAKING CHANGE: engine, detail_threshold and simplify_move_markup are
removed from DocxodusEngine.run_redline() and raise ValueError.

They are rejected rather than dropped, because dropping them would not
be a breaking change but a wrong-answer one. The v12 CLI rejects
--engine as an unknown flag and merely warns-and-ignores the other two,
so a caller passing engine="wmlcomparer" would have silently received
DocxDiff output believing they had selected something else. Unknown
keyword arguments are rejected on the same reasoning: a typo used to be
discarded in silence, which is indistinguishable from a setting that
did nothing.

The GitHub Action's `comparison` input maps onto the deleted selector
and now fails the run for the same reason.

XmlPowerToolsEngine wraps the *original* Open-XML-PowerTools
WmlComparer in a separately published wheel. It keeps working and keeps
shipping; instantiating it now warns that it is on the way out.

Also fixes two bugs in BaseEngine.run_redline's temp-file handling:

- #30: the output scratch file was NamedTemporaryFile(delete=False).name,
  which drops the only reference to the file object. Its finalizer
  reports a ResourceWarning on CPython 3.13+ and the descriptor stays
  open until collection. Now mkstemp, which is the right tool when only
  a path is wanted.

- Path inputs were registered for deletion alongside the engine's own
  scratch files, so passing a path — a documented input mode that the
  quickstart demonstrates — deleted the caller's source documents. Only
  files this library creates are cleaned up now.

Revision counts on the fixtures are re-pinned to 10, measured against a
freshly built v12.1.0 binary. It is neither the 9 the old default
reported nor the 11 the old opt-in reported: v11 and v12 changed region
arrangement, surplus table cells and section defaults.

Fixes #30

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ed9PC7DDco5AFPjsZyy9F
The README described three ways to compare across two engine classes; two
of those three are gone. It now describes two engine classes, one
algorithm each, and carries an "Upgrading to 1.0.0" section covering the
removed keyword arguments, the re-baselined revision count, and the
input-revision policy change that this project's fixtures cannot warn
anyone about.

The Action self-test no longer asserts an exact revision count. That
workflow installs python-redlines from PyPI, so the number it sees
tracks the published version rather than the branch under test — pinning
it to 10 here would fail every run until 1.0.0 ships, and pinning it to 9
would fail every run afterwards. It asserts a positive count, which is
what "the action plumbing works" actually means; the exact count is
pinned in tests/test_docxodus_engine.py, which runs against the working
tree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ed9PC7DDco5AFPjsZyy9F
Development Status moves from 4 - Beta to 5 - Production/Stable, which is
what shipping a 1.0.0 asserts.

The `ooxmlpowertools` extra now says in the file that it installs a
deprecated engine. `all` deliberately keeps installing it: the extra
exists so that anyone who needs the original WmlComparer's output has
somewhere to stand, and quietly changing what `all` resolves to would
break existing pins to make a point.

Drops the brainstorming design doc from the branch — its substance lives
in the previous commit message, the PR body, and the README's
"Upgrading to 1.0.0" section, and a published package's repo is not the
place for a process artifact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ed9PC7DDco5AFPjsZyy9F
@JSv4
JSv4 merged commit b368d3d into main Sep 6, 2026
15 checks passed
@JSv4
JSv4 deleted the upgrade-docxodus-v12 branch September 6, 2026 13:05
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.

run_redline leaks a NamedTemporaryFile object, causing a ResourceWarning on Python 3.13+

1 participant