Graphtage 0.4.0 is the first release since January 2024. It adds TOML and INI support, raises the minimum Python version to 3.10, moves the project to pyproject.toml, and fixes a long list of correctness bugs in the diff core and the formatters.
Breaking changes
- Python 3.10 or later is required. Graphtage is tested against Python 3.10 through 3.14 (#141).
graphtage.version.__version__is a string rather than a tuple.__version_tuple__keeps the old shape, andDEV_BUILDis gone along with the git branch version suffix.BuildOptions(check_for_cyces=…)is misspelled and deprecated. Usecheck_for_cycles; the old keyword still works and warns (#167, closes #157).- The macOS binary attached to this release is arm64. GitHub's macOS runners no longer produce x86_64 builds, so install from PyPI on Intel Macs.
New file formats
- TOML (#97, closes #16), including edit markup for tables that a diff adds, removes, or replaces (#178, #182).
- INI (#120, #138, closes #49). Thanks to @0xTaoZ.
New features
graphtage-git-diff, a git external diff driver, with setup instructions in the README (#129, closes #22).--ignore-list-orderdiffs lists as unordered collections (#131, closes #56).- Errors exit with a status distinct from "a diff was found".
--no-statusand--quietsuppress the progress bar (#135, closes #133).--coloris honored when STDOUT is redirected (#130, closes #128).
Performance
EditDistanceselects optimal Levenshtein paths, fixing suboptimal edit costs (#132, closes #89).- Multiset equality is linear in nesting depth rather than exponential (#136).
- Cached edit bounds (#111), heap-based
make_distinct()(#110), lazy progress bars (#109), and__slots__on hot classes (#108).
Bug fixes
- Diffing a dictionary against a set no longer raises
AttributeError(#127, closes #126). --to-mimeis no longer ignored in favor of--from-mime.--match-ifmatches the semantics its help text describes (#168, closes #148).--join-dict-itemsno longer indents nested sequences (#169, closes #158).- A
Replaceinside a list prints once instead of twice (#170, closes #152). - Closing STDOUT early exits quietly instead of raising
BrokenPipeError(#171, closes #156). -dumpversionprints0.4.0rather than0 . 4 . 0(#161, closes #147).DataClassNodekeeps every base's slots under multiple inheritance (#175, #180, closes #173). Thanks to @Liyu0310-Code.DataClassNode.post_init()runs for the class being instantiated (#166, closes #149), edits keep node syntax when printed (#162, closes #150), andprint()no longer raises onFore.Yellow(#163, closes #153).- In
graphtage.ast:Subscriptrenders correctly in both printing paths (#164, closes #154, thanks to @YusufT0), attribute receivers are unquoted (#159, closes #155, thanks to @1cbyc), import aliases are unquoted (#176, closes #172), andASTBuilderhandles plainimportstatements (#165, closes #151). - A JSON5 parse error no longer raises
TypeErroron the error path. - The standalone binaries no longer exit with
NameError: name 'exit' is not defined. A PyInstaller build runs without thesitemodule that providesexit.
Packaging and infrastructure
- Migrated to
pyproject.tomlwith hatchling, fixing installation on Python 3.12 and later (#93, #92, closes #91, #52). Thanks to @dguido. - PyPI uploads use Trusted Publishing with PEP 740 attestations (#114). Thanks to @facutuesca.
- CI gates on ruff, treats Sphinx warnings as errors, and checks
uv.lock. - Test data is seeded, so fuzz iterations are reproducible and no longer stall CI (#134).
Documentation
- Rewrote the library, builder, printing, and how-it-works guides, refreshed the README examples, and documented the command line options, the build options, and the checklists for adding a filetype and cutting a release (#144, #145, #146).
Full changelog: v0.3.1...v0.4.0