Skip to content

Add a sync/apply-dict operation that diffs and patches minimally #25

@nathanjmcdougall

Description

@nathanjmcdougall

Problem

A common pattern when editing YAML config files is:

  1. Parse the document into a Python dict (a model)
  2. Mutate the model in Python
  3. Write it back, preserving comments and formatting

With yamltrip today, step 3 requires manually orchestrating individual upsert, replace, append, remove, and remove_from_list calls for each change. This is verbose and error-prone compared to the old ruamel.yaml approach of mutating a CommentedMap in place and dumping it.

Proposal

Add a sync method that takes a desired Python value, diffs it against the current document content at a given path, and applies the minimal set of patches:

# Scalar/mapping sync — straightforward recursive diff
doc2 = doc.sync('ci', value={'autofix_prs': False, 'skip': ['codespell']})

# List sync with identity key — matches items by a field rather than position
doc2 = doc.sync('repos', value=new_repos, identity_key='repo')

Diff strategy

Change type Patch generated Comments preserved?
New mapping key upsert Yes
Removed mapping key remove Yes
Scalar value changed replace at path Yes
Nested mapping changed Recurse deeper Yes
List item appended append Yes
List item removed remove_from_list Yes
List item inserted (needs insert_at) Depends on #24 Yes

The list-diffing challenge

Without an identity key, list diffing is ambiguous. The identity_key parameter tells sync how to match old and new items (e.g. match pre-commit repos by their repo URL, hooks by their id field). Items matched by identity are diffed recursively; unmatched old items are removed; unmatched new items are appended (or inserted, once #24 lands).

Use case

In usethis, the pre-commit integration previously did:

model.repos.append(new_repo)
mgr.commit_model(model)  # diffs and writes back

After migrating to yamltrip, this became multiple lines of manual patch orchestration. A sync method would restore the simplicity while keeping yamltrip's comment-preservation guarantees.

Notes

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions