feat: handle hybrid Poetry v2 dependency updates#14658
Merged
markhallen merged 11 commits intomainfrom Apr 9, 2026
Merged
Conversation
Add two fixture files for testing hybrid Poetry v2 projects: - pep621_hybrid_version_in_both.toml: dep in both project.dependencies and tool.poetry.dependencies with version specifiers in both - pep621_hybrid_enrichment_only.toml: dep in project.dependencies with enrichment-only entry (no version key) in tool.poetry.dependencies
When a dependency exists in both project.dependencies (PEP 621) and tool.poetry.dependencies, Dependabot must update both consistently. Changes: - Add include? guard in replace_dep so the Poetry declaration_regex falls through to the PEP 621 regex when the matched line doesn't contain the old requirement string - Add freeze_pep621_deps! class method to PyprojectPreparer to pin PEP 621 deps during lockfile regeneration - Add freeze_pep621_top_level_deps! to freeze non-target PEP 621 deps to their locked versions in freeze_top_level_dependencies_except - Call freeze_pep621_deps! from freeze_dependencies_being_updated Closes github/dependabot-updates#12980
Add tests for hybrid projects in poetry_file_updater_spec.rb: - Version in both sections: both project.dependencies and tool.poetry.dependencies are updated consistently - Enrichment-only: only project.dependencies is updated, tool.poetry.dependencies enrichment entry is preserved Add tests for PEP 621 freeze in pyproject_preparer_spec.rb: - Freezes PEP 621 deps to locked versions - Freezes tool.poetry.dependencies alongside PEP 621 - Respects excluded dependencies
Contributor
There was a problem hiding this comment.
Pull request overview
Adds Poetry v2 “hybrid” support to the Python Poetry updater so Dependabot can correctly update and freeze dependencies declared in both PEP 621 ([project]) and Poetry’s legacy tables ([tool.poetry]).
Changes:
- Adjusts
replace_depto fall through to PEP 621 matching when a[tool.poetry.*]match doesn’t actually contain the old requirement string. - Extends freezing logic to cover PEP 621
project.dependencies/project.optional-dependenciesduring lockfile regeneration. - Adds fixtures and specs covering hybrid update behavior and PEP 621 freezing.
Show a summary per file
| File | Description |
|---|---|
| python/lib/dependabot/python/file_updater/poetry_file_updater.rb | Fixes replace_dep fallthrough and freezes PEP 621 deps during update. |
| python/lib/dependabot/python/file_updater/pyproject_preparer.rb | Implements PEP 621 freezing/pinning helpers and integrates them into top-level freezing. |
| python/spec/dependabot/python/file_updater/poetry_file_updater_spec.rb | Adds hybrid project update coverage (both sections updated; enrichment preserved). |
| python/spec/dependabot/python/file_updater/pyproject_preparer_spec.rb | Adds coverage for freezing PEP 621 project.dependencies alongside Poetry deps. |
| python/spec/fixtures/pyproject_files/pep621_hybrid_version_in_both.toml | Fixture for hybrid dependency with versions in both sections. |
| python/spec/fixtures/pyproject_files/pep621_hybrid_enrichment_only.toml | Fixture for hybrid dependency with enrichment-only Poetry entry. |
Copilot's findings
- Files reviewed: 6/6 changed files
- Comments generated: 3
- Handle bare deps without version specifiers by appending ==version - Preserve whitespace before environment markers using non-greedy regex - Make pin_pep621_dep_in_arrays! a private class method - Use consistent name-matching regex in freeze_pep621_dep_array! - Remove unused named capture group and redundant && dep.version - Add tests for environment markers and optional-dependencies
- Add explicit block parameter to freeze_pep621_deps! sig and def - Wrap match[1] in T.must for nilability checks in freeze_pep621_dep_array!
- Extract shared pep508_name_pattern and pin_pep508_entry helpers - Handle underscores and dots in PEP 508 name matching (not just hyphens) - Guard enrichment-only Poetry entries from version injection - Restore original method chain formatting
- Use explicit block variable check with yield to satisfy both Performance/BlockGivenWithExplicitBlock and RedundantBlockCall - Compact delegation methods to reduce PoetryFileUpdater class length below Metrics/ClassLength limit (350)
…sion test - Extract collect_pep621_dep_arrays to validate that dep_arrays entries guarding against unexpected TOML values at runtime. - Add test coverage for excluded dependencies within project.optional-dependencies.
robaiken
approved these changes
Apr 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What are you trying to accomplish?
Poetry v2 supports declaring dependencies in both
project.dependencies(PEP 621) andtool.poetry.dependenciessimultaneously:Here
project.dependenciesprovides the version for package metadata, andtool.poetry.dependenciesenriches it with source/marker info for locking. When Dependabot updates a dependency, it must update the version inproject.dependenciesAND update the version intool.poetry.dependencies(if it contains aversionkey), while leaving enrichment-only entries (noversionkey) unchanged.Before this PR, the updater had two gaps:
replace_depwould match the[tool.poetry.dependencies]header viadeclaration_regexbut fail to find the PEP 621 requirement string in the matched declaration, returning unchanged content without falling through to thepep621_declaration_regex.freeze_dependencies_being_updatedandfreeze_top_level_dependencies_exceptonly froze deps intool.poetry.*— PEP 621project.dependencieswere left unfrozen during lockfile regeneration, potentially causing incorrect lock resolution.Closes github/dependabot-updates#12980
Anything you want to highlight for special attention from reviewers?
replace_depguard change (poetry_file_updater.rb L127): Addedinclude?(old_req)check before returning from the Poetrydeclaration_regexmatch. This changes the fallthrough behavior — previously a no-op.sub()would return unchanged content, now it falls through to try the PEP 621 regex. For pure Poetry v1 projects (no[project]section), the PEP 621 regex won't match either, so the result is identical. Risk is limited to edge cases wheredeclaration_regexmatches a header but the requirement string differs from what the parser reported.Freeze logic split:
freeze_pep621_deps!is a class method onPyprojectPreparer(used by both the updater'sfreeze_dependencies_being_updatedand the preparer'sfreeze_top_level_dependencies_except). The instance methodfreeze_pep621_top_level_deps!handles the "freeze everything except excluded deps" case by looking up locked versions from the lockfile.All new code paths guard on
pyproject_object["project"]being present — pure Poetry v1 projects without a[project]section are completely unaffected.How will you know you've accomplished your goal?
All tests pass (71 examples, 0 failures) including 9 new tests:
poetry_file_updater_spec.rb— 6 new tests:project.dependenciesandtool.poetry.dependenciesare updatedproject.dependenciesis updated, enrichment entry preservedpyproject_preparer_spec.rb— 3 new tests:Checklist