Uh oh!
There was an error while loading. Please reload this page.
Simplify manifest class - #1111
Conversation
WalkthroughReplaced Manifest.update_dump() usages with Manifest.dump(); refactored Manifest to derive projects/remotes from the live ruamel YAML document; introduced ManifestBuilder for manifest construction/formatting; added ProjectEntry.from_raw; adjusted manifest dumping API, string normalization, and tests. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as "CLI (add/freeze/import)"
participant Manifest as "Manifest / ManifestBuilder"
participant FS as "Filesystem"
CLI->>Manifest: append_project_entry(...) / build()
Note right of Manifest: mutate ruamel YAML doc or assemble YAML string
Manifest->>Manifest: normalize string scalars & adjust spacing
Manifest->>FS: dump(path) — write YAML to file
FS-->>Manifest: write OK
Manifest-->>CLI: return success
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dfetch/manifest/manifest.py`:
- Around line 343-358: The projects property rebuilds the project list on every
access causing duplicate work because selected_projects calls self.projects and
then _check_all_names_found calls it again; modify selected_projects to reuse
the already-computed list by passing the local all_projects into the checker (or
update _check_all_names_found to accept an optional projects sequence) instead
of letting _check_all_names_found call self.projects again; touch the
selected_projects method and the _check_all_names_found signature/usage to
accept and use the passed projects to avoid double rebuilds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6fd6b95c-2739-46c7-8506-049b4a093de1
📒 Files selected for processing (6)
dfetch/commands/add.pydfetch/commands/freeze.pydfetch/commands/import_.pydfetch/manifest/manifest.pytests/test_add.pytests/test_manifest.py
Uh oh!
There was an error while loading. Please reload this page.
5b9b3a2 to
6e29cdbCompareThere was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dfetch/manifest/manifest.py`:
- Around line 262-266: Re-run the spacing and quoting normalizers right before
any serialization so mutations (from append_project_entry and
update_project_version) can't bypass them: call self._ensure_section_spacing()
and self._normalize_string_scalars() at the start of dump() (and similarly
before the immediate serialization path around the other serialize call at the
425-435 area), and/or invoke those two helpers at the end of
append_project_entry() and update_project_version() so the document is
normalized before being written.
- Around line 250-252: The current check calls _ensure_unique(projects_raw,
"dst", "manifest.projects") which only inspects explicit dst keys and misses
collisions where ProjectEntry.__init__ defaults dst to name; update the
validation to compute each project's effective destination (use dst if present
else name) from projects_raw and pass that list or a synthetic field to
_ensure_unique (or call _ensure_unique with the computed values) so duplicates
like a project with no dst and another with dst equal to that name are detected
and rejected.
- Around line 86-92: When clearing potential spurious blank tokens from
parent.ca.items for a given key (the code using parent.ca.items.get(key) and
touching indices [2] and [3]), first inspect the token objects at those
positions and only set them to None if they contain purely whitespace/newlines
(no '#' character) to avoid deleting user comments; similarly update the
analogous logic around the later block that touches indices at lines ~112-115.
Locate the CommentToken (or whatever token object is present) at parent_items[2]
and parent_items[3], examine their string content for a '#' (or non-whitespace)
and preserve the token if it contains a user comment, otherwise clear it as
before. Ensure both places in manifest.py use this same guarded check so user
comments between keys (e.g., between integrity/hash or patch/first item) are
retained.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: e0f8cd0e-039f-4abd-a803-a261d8f6b215
📒 Files selected for processing (7)
dfetch/commands/add.pydfetch/commands/freeze.pydfetch/commands/import_.pydfetch/manifest/manifest.pydfetch/manifest/project.pytests/test_add.pytests/test_manifest.py
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/test_manifest.py (1)
420-425: 🧹 Nitpick | 🔵 TrivialTest
dump(), not_doc.as_yaml().The renamed test still bypasses the public API, so it will not catch regressions in
Manifest.dump()itself. Usingmock_open()keeps the assertion aligned with the behavior that changed in this PR.♻️ Suggested change
def test_dump_writes_version_as_quoted_string(manifest_text: str) -> None: """dump must always write version as a quoted YAML string.""" manifest = Manifest.from_yaml(manifest_text) - result = manifest._doc.as_yaml()+ with patch("dfetch.manifest.manifest.open", mock_open()) as mocked_open:+ manifest.dump(DEFAULT_MANIFEST_NAME)+ result = "".join(call.args[0] for call in mocked_open().write.call_args_list) # The version value must appear quoted so that YAML parsers read it as a string. assert f"version: '{manifest.version}'" in result🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_manifest.py` around lines 420 - 425, The test currently calls manifest._doc.as_yaml() instead of the public API; change test_dump_writes_version_as_quoted_string to call Manifest.dump() and capture its output using mock_open (or a tmp file fixture) so you assert against what dump actually writes; locate the test function test_dump_writes_version_as_quoted_string and replace the _doc.as_yaml() usage with a call to manifest.dump() while using mock_open()/patch on builtins.open (or the test's tmp file writer) to read the written content and assert that "version: '<manifest.version>'" appears in that captured output.
♻️ Duplicate comments (2)
dfetch/manifest/manifest.py (2)
354-364:⚠️ Potential issue | 🟠 MajorNormalize the live document immediately before
dump().
_normalize_string_scalars()only runs during construction. After later mutations likeappend_project_entry(), new YAML values are plainstrs again, sodump()can write"176"/"%feature"back unquoted and change how they parse on the next load.♻️ Proposed fix
def dump(self, path: str | None = None) -> None: """Write the manifest to *path*, preserving formatting and comments. @@ + self._normalize_string_scalars()+ target = path or self.__path if not target: raise RuntimeError("Cannot dump manifest with no path")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dfetch/manifest/manifest.py` around lines 354 - 364, The dump method may write newly added/modified string scalars without the normalization applied at construction, causing values like "176" or "%feature" to be emitted unquoted; before writing in dump (method dump in class Manifest), call the existing normalization routine (e.g. _normalize_string_scalars) to re-normalize the live YAML document so string scalars get proper tagging/quoting; ensure this is applied right before manifest_file.write(self._doc.as_yaml()) so mutations from methods like append_project_entry are normalized prior to serializing.
182-184:⚠️ Potential issue | 🟠 MajorCheck uniqueness on the effective
dst, not just explicit keys.
_ensure_unique(projects_raw, "dst", ...)skips entries that omitdst, but those still resolve toname. A manifest containing- name: fooand- name: bar; dst: foopasses validation and still makes both projects target the same destination.♻️ Proposed fix
_ensure_unique(remotes_raw, "name", "manifest.remotes") _ensure_unique(projects_raw, "name", "manifest.projects") - _ensure_unique(projects_raw, "dst", "manifest.projects")+ _ensure_unique(+ [+ {"dst": project.get("dst", project["name"])}+ for project in projects_raw+ ],+ "dst",+ "manifest.projects",+ )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dfetch/manifest/manifest.py` around lines 182 - 184, The uniqueness check currently calls _ensure_unique(projects_raw, "dst", "manifest.projects") which ignores entries that lack an explicit "dst" (they effectively use their "name"), so compute the effective destination for each project (e.g., effective_dst = project.get("dst") or project["name"]) and run the uniqueness check against those effective values; update the validation to either build a list of effective dsts and call _ensure_unique on that list or modify _ensure_unique to accept a fallback key/resolver for projects_raw so that collisions between explicit dst and defaulted name are detected for manifest.projects.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dfetch/manifest/manifest.py`:
- Around line 395-403: The function _normalize_string_scalars currently only
wraps top-level mapping values under manifest_mu.get("projects") and
manifest_mu.get("remotes") with _yaml_str, missing nested strings (e.g.,
integrity.hash and list items like ignore); update _normalize_string_scalars to
recursively traverse mappings and sequences within each entry so every string
value encountered is passed to _yaml_str (not just direct values), preserving
existing calls for project and remote entries while ensuring nested dict keys
and list items are normalized too.
---
Outside diff comments:
In `@tests/test_manifest.py`:
- Around line 420-425: The test currently calls manifest._doc.as_yaml() instead
of the public API; change test_dump_writes_version_as_quoted_string to call
Manifest.dump() and capture its output using mock_open (or a tmp file fixture)
so you assert against what dump actually writes; locate the test function
test_dump_writes_version_as_quoted_string and replace the _doc.as_yaml() usage
with a call to manifest.dump() while using mock_open()/patch on builtins.open
(or the test's tmp file writer) to read the written content and assert that
"version: '<manifest.version>'" appears in that captured output.
---
Duplicate comments:
In `@dfetch/manifest/manifest.py`:
- Around line 354-364: The dump method may write newly added/modified string
scalars without the normalization applied at construction, causing values like
"176" or "%feature" to be emitted unquoted; before writing in dump (method dump
in class Manifest), call the existing normalization routine (e.g.
_normalize_string_scalars) to re-normalize the live YAML document so string
scalars get proper tagging/quoting; ensure this is applied right before
manifest_file.write(self._doc.as_yaml()) so mutations from methods like
append_project_entry are normalized prior to serializing.
- Around line 182-184: The uniqueness check currently calls
_ensure_unique(projects_raw, "dst", "manifest.projects") which ignores entries
that lack an explicit "dst" (they effectively use their "name"), so compute the
effective destination for each project (e.g., effective_dst = project.get("dst")
or project["name"]) and run the uniqueness check against those effective values;
update the validation to either build a list of effective dsts and call
_ensure_unique on that list or modify _ensure_unique to accept a fallback
key/resolver for projects_raw so that collisions between explicit dst and
defaulted name are detected for manifest.projects.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4b29e911-e230-4cae-8472-14419d10b4ad
📒 Files selected for processing (4)
dfetch/commands/import_.pydfetch/manifest/manifest.pytests/test_import.pytests/test_manifest.py
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dfetch/manifest/manifest.py`:
- Around line 594-614: The substitution in _render that inserts blank lines
between list entries is too permissive (parts loop using re.sub(r"\n( - )",
...)), which can match ` - ` inside multi-line scalar values; tighten the regex
to only target actual sequence-item line starts—e.g. replace that re.sub with
one using a multiline/anchored pattern such as re.sub(r"(?m)^\s{2}- ", r"\n\n -
", parts[i]) or use a lookahead like r"\n( - (?=\S))" so only true list-item
lines in the parts variable are matched and modified.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2286969b-260f-4832-8225-5d4b057e7ee2
📒 Files selected for processing (2)
dfetch/manifest/manifest.pytests/test_manifest.py
Uh oh!
There was an error while loading. Please reload this page.
Summary by CodeRabbit
Improvements
Bug Fixes