Skip to content

0.4.0: save(document) and serialize(document); serialize_document deprecated - #99

Merged
dvejsada merged 1 commit into
mainfrom
claude/jolly-johnson-e3yr9u
Oct 3, 2026
Merged

dvejsada merged 1 commit into
mainfrom
claude/jolly-johnson-e3yr9u

Conversation

@dvejsada

@dvejsada dvejsada commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Writing a document now mirrors reading it. This is the last workflow piece of the 0.4.0 API simplification.

from legaldown import load, save

document = load("contract.lgd")
document.metadata.governing_law = "Czech Republic"
save(document)                 # back to contract.lgd

Changes

save(document, path=None) -> Path

  • It writes the document to path, or, when no path is given, back to document.path (where load found it). A document from parse(text) or built in code has no path, so it gets ValueError until one is passed.
  • The write is atomic: a temporary file beside the target is moved into place, so the file is either the old text or the new.
    • A symbolic link is written through.
    • The file keeps its permissions; a new file gets the umask default.
    • Missing directories are created.
  • The text is UTF-8 with LF line endings and no BOM, so a file read with CRLF or a BOM is written back without them. The docstring and README say so.
  • Afterwards the document lives at the path written, as after load: document.path and document.filename follow it. That matters because validate reads an amended original or attachment definitions from beside document.path, and diagnostics name the filename. On failure, both are unchanged.

serialize(document) -> str

  • The text, the inverse of parse.
  • serialize_document still works but raises a DeprecationWarning. Like parse_document and validate_document, it is deprecated since 0.4.0 and will be removed in 0.5.0.

Shared atomic writer

  • The writer --save-answers already used moves from cli.py to files.write_atomically, which is not exported, and now serves both. The CLI's behaviour is unchanged.

Docs

  • The README's editing example is load → edit → save(document), with a paragraph on what save guarantees. The quick start prints serialize(document), so running it does not rewrite your file.
  • The deprecation note lists serialize_document.

Verification

  • 2985 tests pass with the spec fixtures corpus (24 new in tests/test_save.py, plus the deprecation test). ruff is clean.
  • tests/test_save.py covers:
    • the round trip, saving back to the file and saving to a new path;
    • ValueError without a path, str and PathLike paths, and creating directories;
    • validate reading from beside the new path;
    • CRLF, CR and BOM input written as LF without a BOM;
    • a failure mid-write leaving the file as it was with no temporary file left behind;
    • symbolic links, kept permission bits, and the umask mode for a new file.
  • All 160 spec fixture documents give byte-identical validation results to main.
  • The existing tests now call serialize. serialize_document remains only in the deprecated wrapper, its export, the deprecation note and its test.

🤖 Generated with Claude Code

https://claude.ai/code/session_013WmBAc5T7UCKVdpUmg9qxz


Generated by Claude Code

… deprecated

Writing a document now mirrors reading it: `load(path)` → edit →
`save(document)` writes it back to `document.path` (or to a given path,
which the document then lives at: `path` and `filename` follow, as after
`load`). The write is atomic — a temporary file beside it, moved into
place — writes through a symbolic link, keeps the file's permissions,
and creates missing directories; the text is UTF-8, LF, no BOM. The
atomic writer `--save-answers` used moves from cli.py to files.py and
serves both.

`serialize(document)` is the text, the inverse of `parse`.
`serialize_document` still works, with a DeprecationWarning; deprecated
since 0.4.0, removed in 0.5.0, like `parse_document` and
`validate_document`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013WmBAc5T7UCKVdpUmg9qxz
@dvejsada dvejsada added the ci label Oct 3, 2026 — with Claude
@dvejsada
dvejsada merged commit e19d7c2 into main Oct 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants