feat(cli): Support PEP 735 (Dependency Groups)#10130
feat(cli): Support PEP 735 (Dependency Groups)#10130radoering merged 7 commits intopython-poetry:mainfrom
Conversation
Reviewer's GuideImplement PEP 735 support by introducing a top-level dependency-groups section and extending CLI commands, project layout, self-commands, tests, and documentation to read/write both PEP 735 and legacy tool.poetry.group formats. Entity Relationship diagram for dependency group sections in pyproject.tomlerDiagram
PYPROJECT_TOML {
string version
string description
string requires-python
array dependencies
}
DEPENDENCY_GROUPS {
array group_name
array dependencies
}
TOOL_POETRY {
array packages
}
TOOL_POETRY_GROUP {
string group_name
boolean optional
array dependencies
}
PYPROJECT_TOML ||--|{ DEPENDENCY_GROUPS : "has"
PYPROJECT_TOML ||--|{ TOOL_POETRY : "has"
TOOL_POETRY ||--|{ TOOL_POETRY_GROUP : "has"
DEPENDENCY_GROUPS ||--|{ TOOL_POETRY_GROUP : "legacy fallback"
Class diagram for updated add/remove command logicclassDiagram
class AddCommand {
+handle()
-use_project_section: bool
-use_groups_section: bool
-groups_content
-project_content
-poetry_content
}
class RemoveCommand {
+handle()
-groups_content
-poetry_groups_content
-_remove_packages()
}
AddCommand --> "reads/writes" groups_content
RemoveCommand --> "reads/writes" groups_content
RemoveCommand --> "reads/writes" poetry_groups_content
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
f468fca to
eeb4814
Compare
|
@sourcery-ai review |
bacef77 to
ee49998
Compare
|
Deploy preview for website ready! Built with commit b85f0a9. |
radoering
left a comment
There was a problem hiding this comment.
Some feedback:
- To satisfy the export tests, you can try to add
poetry remove --lock poetry-coreinpoetry/.github/workflows/.tests-matrix.yaml
Line 115 in 9af386a
- The
support pep 735commit is missing a test forremoveand the tests intest_remove_pluginsare stillxfail. (If this is still on your todo list ignore the comment).
93e9c7e to
628c412
Compare
720e60f to
727e441
Compare
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey @finswimmer - I've reviewed your changes - here's some feedback:
Overall Comments:
- The remove command does not fully support the new dependency-groups format yet, as evidenced by the xfailed tests. This should be implemented before merging.
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟢 Security: all looks good
- 🟡 Testing: 2 issues found
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
727e441 to
1c9ed30
Compare
4642fc2 to
38f0b35
Compare
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey @finswimmer - I've reviewed your changes - here's some feedback:
Overall Comments:
- Extract the common dependency-group setup logic from tests into helper functions to reduce duplication in the if-else blocks.
- Refactor the repeated type casts and handling of groups_content to improve code readability and maintainability.
Here's what I looked at during the review
- 🟡 General issues: 2 issues found
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
bf31cc9 to
db3ee35
Compare
There was a problem hiding this comment.
Hey @finswimmer - I've reviewed your changes - here's some feedback:
- The add/remove command handlers are now very lengthy with repeated PEP 735 branching—extract the core dependency-group logic into dedicated helper methods or classes to simplify and DRY up the code.
- There’s a lot of duplicated test setup for PEP 735 vs legacy behavior; consolidate that into fixtures or helper functions to reduce boilerplate and make the intent clearer.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The add/remove command handlers are now very lengthy with repeated PEP 735 branching—extract the core dependency-group logic into dedicated helper methods or classes to simplify and DRY up the code.
- There’s a lot of duplicated test setup for PEP 735 vs legacy behavior; consolidate that into fixtures or helper functions to reduce boilerplate and make the intent clearer.
## Individual Comments
### Comment 1
<location> `tests/console/commands/self/test_add_plugins.py:27` </location>
<code_context>
def assert_plugin_add_result(
tester: CommandTester,
expected: str,
</code_context>
<issue_to_address>
Test assertion helper updated for new dependency group format.
Please add a test case with multiple plugins to verify correct array handling.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
radoering
left a comment
There was a problem hiding this comment.
Looks quite good so far. I will do some exploratory testing later.
Just one small thing: I think we should add a test for poetry remove similar to test_remove_from_project_and_poetry for dependencies with additional information in the tool.poetry section.
b4dd08e to
68ea96c
Compare
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey there - I've reviewed your changes - here's some feedback:
- Extract the repeated pep_735 parameterization and assertion blocks in tests into shared fixtures or helper functions to reduce boilerplate and improve maintainability.
- Refactor the add/remove command handle() methods to encapsulate PEP 735 vs legacy group manipulation into helper utilities, reducing deep branching and improving readability.
- Unify or parameterize the two factory methods create_pyproject_from_package and create_legacy_pyproject_from_package to avoid duplicating similar pyproject generation logic.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Extract the repeated pep_735 parameterization and assertion blocks in tests into shared fixtures or helper functions to reduce boilerplate and improve maintainability.
- Refactor the add/remove command handle() methods to encapsulate PEP 735 vs legacy group manipulation into helper utilities, reducing deep branching and improving readability.
- Unify or parameterize the two factory methods create_pyproject_from_package and create_legacy_pyproject_from_package to avoid duplicating similar pyproject generation logic.
## Individual Comments
### Comment 1
<location> `tests/console/commands/test_add.py:671` </location>
<code_context>
+ ]
+
+
+def test_add_to_group_with_latest_overwrite_existing(
+ app: PoetryTestApplication, tester: CommandTester
+) -> None:
</code_context>
<issue_to_address>
Consider adding a test for adding a dependency with a lower version than the existing one.
Please add a test to confirm that adding a lower version does not unintentionally downgrade the dependency, unless this is the desired behavior.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
def test_add_to_group_with_latest_overwrite_existing(
app: PoetryTestApplication, tester: CommandTester
) -> None:
=======
def test_add_to_group_with_latest_overwrite_existing(
app: PoetryTestApplication, tester: CommandTester
) -> None:
def test_add_to_group_with_lower_version_does_not_downgrade(
app: PoetryTestApplication, tester: CommandTester
) -> None:
# Setup: Add a dependency with a higher version first
tester.execute(
"add cachy@^0.2.0 --group example",
app=app,
)
# Try to add a lower version
tester.execute(
"add [email protected] --group example",
app=app,
)
pyproject = app.poetry.file.read()
pyproject = cast("dict[str, Any]", pyproject)
# Assert that the dependency is not downgraded
assert "example" in pyproject["dependency-groups"]
# The version should still be >=0.2.0,<0.3.0, not downgraded to 0.1.0
assert any("cachy (>=0.2.0,<0.3.0)" in dep for dep in pyproject["dependency-groups"]["example"])
assert not any("cachy (==0.1.0)" in dep for dep in pyproject["dependency-groups"]["example"])
>>>>>>> REPLACE
</suggested_fix>
### Comment 2
<location> `tests/console/commands/test_add.py:732` </location>
<code_context>
+ ]
+
+
+def test_add_to_group_uses_existing_legacy_group(
+ app: PoetryTestApplication, tester: CommandTester
+) -> None:
</code_context>
<issue_to_address>
Consider adding a test for conflicting dependency names between legacy and PEP 735 groups.
Please add a test to verify that updates target the correct group when a dependency name appears in both a legacy and a PEP 735 group.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
def test_add_to_group_uses_existing_legacy_group(
app: PoetryTestApplication, tester: CommandTester
) -> None:
=======
def test_add_to_group_uses_existing_legacy_group(
app: PoetryTestApplication, tester: CommandTester
) -> None:
# existing test code...
def test_add_to_group_with_conflicting_dependency_names(
app: PoetryTestApplication, tester: CommandTester
) -> None:
"""
Test that updates target the correct group when a dependency name appears in both
a legacy and a PEP 735 group.
"""
# Setup: Add 'requests' to both a legacy group and a PEP 735 group
pyproject = app.poetry.file.read()
pyproject["dependency-groups"] = {
"legacy": [
"requests (>=2.20.0,<3.0.0)",
],
"pep735": [
"requests (>=2.25.0,<2.26.0)",
],
}
app.poetry.file.write(pyproject)
# Add 'requests' to the 'pep735' group with a new constraint
result = tester.execute(
["add", "requests@^2.25.1", "--group", "pep735"],
app=app,
)
assert result == 0
updated_pyproject = app.poetry.file.read()
# Only the 'pep735' group should be updated
assert updated_pyproject["dependency-groups"]["legacy"] == [
"requests (>=2.20.0,<3.0.0)",
]
assert updated_pyproject["dependency-groups"]["pep735"] == [
"requests (^2.25.1)",
]
>>>>>>> REPLACE
</suggested_fix>
### Comment 3
<location> `tests/console/commands/test_add.py:1332` </location>
<code_context>
-def test_add_to_dev_section(app: PoetryTestApplication, tester: CommandTester) -> None:
+def test_add_to_dev_group(app: PoetryTestApplication, tester: CommandTester) -> None:
tester.execute("cachy --dev")
</code_context>
<issue_to_address>
Consider adding a test for adding to a custom group with special characters in the name.
Test group names containing dots, dashes, or reserved TOML characters to verify proper escaping in pyproject.toml.
</issue_to_address>
### Comment 4
<location> `tests/console/commands/test_remove.py:210` </location>
<code_context>
+ assert expected_poetry_string in string_content
+
+
[email protected]("pep_735", [True, False])
def test_remove_without_specific_group_removes_from_all_groups(
+ pep_735: bool,
tester: CommandTester,
</code_context>
<issue_to_address>
Consider adding a test for removing a dependency that does not exist in any group.
This will verify that the CLI handles non-existent dependencies gracefully and prevents unintended modifications to pyproject.toml.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
assert expected_pep735_string in string_content
assert expected_poetry_string in string_content
=======
assert expected_pep735_string in string_content
assert expected_poetry_string in string_content
@pytest.mark.parametrize("pep_735", [True, False])
def test_remove_nonexistent_dependency_does_not_modify_pyproject(
pep_735: bool,
tester: CommandTester,
app: PoetryTestApplication,
repo: TestRepository,
installed: Repository,
) -> None:
# Setup: pyproject.toml with some dependencies
repo.add_package(Package("foo", "2.0.0"))
repo.add_package(Package("bar", "1.0.0"))
pyproject_before = app.poetry.file.read()
pyproject_before_str = app.poetry.file.as_string()
# Try to remove a dependency that does not exist
result = tester.execute(["remove", "nonexistent-package"])
# Assert: CLI should report not found
assert "nonexistent-package" in result.stdout.lower()
assert "not found" in result.stdout.lower() or "does not exist" in result.stdout.lower()
# Assert: pyproject.toml is unchanged
pyproject_after_str = app.poetry.file.as_string()
assert pyproject_before_str == pyproject_after_str
>>>>>>> REPLACE
</suggested_fix>
### Comment 5
<location> `tests/console/commands/self/utils.py:11` </location>
<code_context>
-def get_self_command_dependencies(locked: bool = True) -> TOMLTable:
+def get_self_command_dependencies(locked: bool = True) -> Array | None:
from poetry.console.commands.self.self_command import SelfCommand
from poetry.locations import CONFIG_DIR
</code_context>
<issue_to_address>
Consider adding a test for the case where no dependency-groups are present in the system pyproject.
This ensures the function correctly returns None without errors when dependency-groups are absent.
</issue_to_address>
### Comment 6
<location> `tests/test_factory.py:167` </location>
<code_context>
poetry = Factory().create_poetry(fixture_dir(project))
package = poetry.package
- pyproject: dict[str, Any] = Factory.create_pyproject_from_package(package)
+ pyproject: dict[str, Any] = Factory.create_legacy_pyproject_from_package(package)
result = pyproject["tool"]["poetry"]
</code_context>
<issue_to_address>
Consider adding a test for the new PEP 735 pyproject generation method.
Only the legacy method is currently tested. Please add a test for the PEP 735-compliant pyproject generation to ensure both formats are validated and to prevent future regressions.
Suggested implementation:
```python
poetry = Factory().create_poetry(fixture_dir(project))
package = poetry.package
# Test legacy pyproject generation
pyproject_legacy: dict[str, Any] = Factory.create_legacy_pyproject_from_package(package)
result_legacy = pyproject_legacy["tool"]["poetry"]
expected = poetry.pyproject.poetry_config
assert result_legacy == expected
# Test PEP 735-compliant pyproject generation
pyproject_pep735: dict[str, Any] = Factory.create_pyproject_from_package(package)
# Adjust the assertion below as needed to match the expected structure for PEP 735
result_pep735 = pyproject_pep735["project"]
# You may need to define the expected PEP 735 structure if it differs from legacy
# For now, we check that the project name matches
assert result_pep735["name"] == expected["name"]
```
If the expected structure for PEP 735 differs significantly from the legacy format, you should define a separate `expected_pep735` variable with the correct expected data for the PEP 735 format and adjust the assertion accordingly.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
5ddab64 to
b0a5e34
Compare
…ependency to [dependency-groups] (python-poetry#10130)
b0a5e34 to
b85f0a9
Compare
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [poetry](https://github.com/python-poetry/poetry) ([changelog](https://python-poetry.org/history/)) | minor | `2.1.4` -> `2.2.1` | --- ### Release Notes <details> <summary>python-poetry/poetry (poetry)</summary> ### [`v2.2.1`](https://github.com/python-poetry/poetry/blob/HEAD/CHANGELOG.md#221---2025-09-21) [Compare Source](python-poetry/poetry@2.2.0...2.2.1) ##### Fixed - Fix an issue where `poetry self show` failed with a message about an invalid output format ([#​10560](python-poetry/poetry#10560)). ##### Docs - Remove outdated statements about dependency groups ([#​10561](python-poetry/poetry#10561)). ##### poetry-core ([`2.2.1`](https://github.com/python-poetry/poetry-core/releases/tag/2.2.1)) - Fix an issue where it was not possible to declare a PEP 735 dependency group as optional ([#​888](python-poetry/poetry-core#888)). ### [`v2.2.0`](https://github.com/python-poetry/poetry/blob/HEAD/CHANGELOG.md#220---2025-09-14) [Compare Source](python-poetry/poetry@2.1.4...2.2.0) ##### Added - **Add support for nesting dependency groups** ([#​10166](python-poetry/poetry#10166)). - **Add support for PEP 735 dependency groups** ([#​10130](python-poetry/poetry#10130)). - **Add support for PEP 639 license clarity** ([#​10413](python-poetry/poetry#10413)). - Add a `--format` option to `poetry show` to alternatively output json format ([#​10487](python-poetry/poetry#10487)). - Add official support for Python 3.14 ([#​10514](python-poetry/poetry#10514)). ##### Changed - **Normalize dependency group names** ([#​10387](python-poetry/poetry#10387)). - Change `installer.no-binary` and `installer.only-binary` so that explicit package names will take precedence over `:all:` ([#​10278](python-poetry/poetry#10278)). - Improve log output during `poetry install` when a wheel is built from source ([#​10404](python-poetry/poetry#10404)). - Improve error message in case a file lock could not be acquired while cloning a git repository ([#​10535](python-poetry/poetry#10535)). - Require `dulwich>=0.24.0` ([#​10492](python-poetry/poetry#10492)). - Allow `virtualenv>=20.33` again ([#​10506](python-poetry/poetry#10506)). - Allow `findpython>=0.7` ([#​10510](python-poetry/poetry#10510)). - Allow `importlib-metadata>=8.7` ([#​10511](python-poetry/poetry#10511)). ##### Fixed - Fix an issue where `poetry new` did not create the project structure in an existing empty directory ([#​10431](python-poetry/poetry#10431)). - Fix an issue where a dependency that was required for a specific Python version was not installed into an environment of a pre-release Python version ([#​10516](python-poetry/poetry#10516)). ##### poetry-core ([`2.2.0`](https://github.com/python-poetry/poetry-core/releases/tag/2.2.0)) - Deprecate table values and values that are not valid SPDX expressions for `[project.license]` ([#​870](python-poetry/poetry-core#870)). - Fix an issue where explicitly included files that are in `.gitignore` were not included in the distribution ([#​874](python-poetry/poetry-core#874)). - Fix an issue where marker operations could result in invalid markers ([#​875](python-poetry/poetry-core#875)). </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS42MC40IiwidXBkYXRlZEluVmVyIjoiNDEuNjAuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> Reviewed-on: https://git.walbeck.it/walbeck-it/docker-python-poetry/pulls/1588 Co-authored-by: renovate-bot <[email protected]> Co-committed-by: renovate-bot <[email protected]>
|
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
poetry-coretomainafter feat: Support PEP 735 dependency groups poetry-core#823 is merged.Pull Request Check List
Requires: python-poetry/poetry-core#823
Resolves: #9751
Summary by Sourcery
Support PEP 735 by adding dependency groups to the pyproject.toml file.
New Features:
Tests:
Summary by Sourcery
Update dependency management to support PEP 735 (Dependency Groups).
New Features:
Tests:
Summary by Sourcery
Implement PEP 735 dependency-groups support across the CLI and project scaffolding while preserving backward compatibility with the existing tool.poetry.group format, update tests and documentation accordingly.
New Features:
Enhancements:
Build:
Documentation:
Tests: