Skip to content

fix: prevent nested dict flattening in _create_at#42

Merged
nathanjmcdougall merged 6 commits into
mainfrom
fix/create-at-nested-dict-flattening
May 24, 2026
Merged

fix: prevent nested dict flattening in _create_at#42
nathanjmcdougall merged 6 commits into
mainfrom
fix/create-at-nested-dict-flattening

Conversation

@nathanjmcdougall
Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where Op.merge_into flattens nested dicts to the wrong indentation level when creating intermediate keys via _create_at.

Problem

When calling upsert("parent", "child", value={"x": 1, "y": 2}) on a document where parent doesn't exist, _create_at builds nested_value = {"child": {"x": 1, "y": 2}} and passes it to Op.merge_into("parent", nested_value). The Rust merge_into operation flattens the nested dict, producing:

parent:
  child:
  x: 1
  y: 2

instead of the correct:

parent:
  child:
    x: 1
    y: 2

Fix

Replace the single Op.merge_into call with a two-step approach:

  1. Op.add(first_key, None) — creates the key with a placeholder
  2. Op.replace(nested_value) on the new path — replaces with the full nested structure

Op.replace correctly serializes complex values, avoiding the flattening.

Testing

Adds a regression test (test_upsert_missing_nested_path_with_dict) that fails without the fix and passes with it. All 351 existing tests continue to pass.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect YAML structure produced by Document.upsert() when creating missing intermediate keys whose value is a nested mapping, avoiding yamlpatch MergeInto’s uniform-indent serialization limitations.

Changes:

  • Update _create_at() to route nested dict/list values through a two-step add placeholder + replace operation instead of merge_into.
  • Add a regression test covering nested dict insertion via intermediate keys.
  • Document merge_into’s flat-only constraint in Rust bindings and update the design spec accordingly.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
tests/test_document.py Adds regression test ensuring nested dict values remain properly nested when upserting through missing intermediate keys.
src/yamltrip/document.py Implements conditional fallback to add + replace to preserve indentation for nested values when creating intermediate keys.
src/ops.rs Documents merge_into as intended for flat/scalar-only updates and advises add + replace for nested values.
doc/specs/2026-05-13-yamltrip-design.md Updates design notes to reflect the flat-vs-nested split in upsert() creation strategy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/yamltrip/document.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread src/yamltrip/document.py Outdated
Comment thread src/ops.rs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread src/ops.rs
Comment thread tests/test_document.py
…s a regression test for list values via intermediate keys.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread src/ops.rs
Comment thread tests/test_document.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread doc/specs/2026-05-13-yamltrip-design.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread src/ops.rs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.

Comment thread src/ops.rs
@nathanjmcdougall nathanjmcdougall merged commit c009316 into main May 24, 2026
19 checks passed
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.

2 participants