Skip to content

Commit 41a7d22

Browse files
committed
fix remove if standard and poetry section is used (#10130)
1 parent bd060f6 commit 41a7d22

File tree

2 files changed

+98
-29
lines changed

2 files changed

+98
-29
lines changed

src/poetry/console/commands/remove.py

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def handle(self) -> int:
6565
project_content = content.get("project", {})
6666
groups_content = content.get("dependency-groups", {})
6767
poetry_content = content.get("tool", {}).get("poetry", {})
68+
poetry_groups_content = poetry_content.get("group", {})
6869

6970
if group is None:
7071
# remove from all groups
@@ -75,42 +76,39 @@ def handle(self) -> int:
7576

7677
if project_dependencies or poetry_dependencies:
7778
group_sections.append(
78-
(MAIN_GROUP, project_dependencies, poetry_dependencies, [])
79+
(MAIN_GROUP, project_dependencies, poetry_dependencies)
7980
)
8081
group_sections.extend(
81-
(group_name, [], {}, dependencies)
82+
(
83+
group_name,
84+
dependencies,
85+
poetry_groups_content.get(group_name, {}).get("dependencies", {}),
86+
)
8287
for group_name, dependencies in groups_content.items()
8388
)
8489
group_sections.extend(
85-
(group_name, [], group_section.get("dependencies", {}), [])
86-
for group_name, group_section in poetry_content.get("group", {}).items()
90+
(group_name, [], group_section.get("dependencies", {}))
91+
for group_name, group_section in poetry_groups_content.items()
92+
if group_name not in groups_content and group_name != MAIN_GROUP
8793
)
8894

89-
for (
90-
group_name,
91-
project_section,
92-
poetry_section,
93-
group_dep_section,
94-
) in group_sections:
95+
for group_name, standard_section, poetry_section in group_sections:
9596
removed |= self._remove_packages(
9697
packages=packages,
97-
project_section=project_section,
98+
standard_section=standard_section,
9899
poetry_section=poetry_section,
99-
group_section=group_dep_section,
100100
group_name=group_name,
101101
)
102102
if group_name != MAIN_GROUP:
103-
if not poetry_section and group_name in poetry_content.get(
104-
"group", {}
105-
):
103+
if not poetry_section and group_name in poetry_groups_content:
106104
del poetry_content["group"][group_name]
107-
if not group_dep_section and group_name in groups_content:
105+
if not standard_section and group_name in groups_content:
108106
del groups_content[group_name]
109107

110108
elif group == "dev" and "dev-dependencies" in poetry_content:
111109
# We need to account for the old `dev-dependencies` section
112110
removed = self._remove_packages(
113-
packages, [], poetry_content["dev-dependencies"], [], "dev"
111+
packages, [], poetry_content["dev-dependencies"], "dev"
114112
)
115113

116114
if not poetry_content["dev-dependencies"]:
@@ -122,11 +120,10 @@ def handle(self) -> int:
122120
removed.update(
123121
self._remove_packages(
124122
packages=packages,
125-
project_section=[],
123+
standard_section=[],
126124
poetry_section=poetry_content["group"][group].get(
127125
"dependencies", {}
128126
),
129-
group_section=[],
130127
group_name=group,
131128
)
132129
)
@@ -137,9 +134,8 @@ def handle(self) -> int:
137134
removed.update(
138135
self._remove_packages(
139136
packages=packages,
140-
project_section=[],
137+
standard_section=groups_content[group],
141138
poetry_section={},
142-
group_section=groups_content[group],
143139
group_name=group,
144140
)
145141
)
@@ -178,28 +174,23 @@ def handle(self) -> int:
178174
def _remove_packages(
179175
self,
180176
packages: list[str],
181-
project_section: list[str],
177+
standard_section: list[str],
182178
poetry_section: dict[str, Any],
183-
group_section: list[str],
184179
group_name: str,
185180
) -> set[str]:
186181
removed = set()
187182
group = self.poetry.package.dependency_group(group_name)
188183

189184
for package in packages:
190185
normalized_name = canonicalize_name(package)
191-
for requirement in project_section.copy():
186+
for requirement in standard_section.copy():
192187
if Dependency.create_from_pep_508(requirement).name == normalized_name:
193-
project_section.remove(requirement)
188+
standard_section.remove(requirement)
194189
removed.add(package)
195190
for existing_package in list(poetry_section):
196191
if canonicalize_name(existing_package) == normalized_name:
197192
del poetry_section[existing_package]
198193
removed.add(package)
199-
for requirement in group_section.copy():
200-
if Dependency.create_from_pep_508(requirement).name == normalized_name:
201-
group_section.remove(requirement)
202-
removed.add(package)
203194

204195
for package in removed:
205196
group.remove_dependency(package)

tests/console/commands/test_remove.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,84 @@ def test_remove_from_project_and_poetry(
129129
assert expected_poetry_string in string_content
130130

131131

132+
def test_remove_from_pep735_group_and_poetry_group(
133+
tester: CommandTester,
134+
app: PoetryTestApplication,
135+
repo: TestRepository,
136+
installed: Repository,
137+
) -> None:
138+
repo.add_package(Package("foo", "2.0.0"))
139+
repo.add_package(Package("bar", "1.0.0"))
140+
141+
pyproject: dict[str, Any] = app.poetry.file.read()
142+
143+
pep735_dependencies: dict[str, Any] = tomlkit.parse(
144+
"""\
145+
[dependency-groups]
146+
dev = [
147+
"foo>=2.0",
148+
"bar>=1.0",
149+
]
150+
"""
151+
)
152+
153+
poetry_dependencies: dict[str, Any] = tomlkit.parse(
154+
"""\
155+
[tool.poetry.group.dev.dependencies]
156+
foo = "^2.0.0"
157+
bar = "^1.0.0"
158+
159+
"""
160+
)
161+
162+
pyproject["dependency-groups"] = pep735_dependencies["dependency-groups"]
163+
pyproject["tool"]["poetry"]["group"] = poetry_dependencies["tool"]["poetry"][
164+
"group"
165+
]
166+
pyproject = cast("TOMLDocument", pyproject)
167+
app.poetry.file.write(pyproject)
168+
169+
app.poetry.package.add_dependency(
170+
Factory.create_dependency("foo", "^2.0.0", groups=["dev"])
171+
)
172+
app.poetry.package.add_dependency(
173+
Factory.create_dependency("bar", "^1.0.0", groups=["dev"])
174+
)
175+
176+
tester.execute("foo")
177+
178+
pyproject = app.poetry.file.read()
179+
pyproject = cast("dict[str, Any]", pyproject)
180+
pep735_dependencies = pyproject["dependency-groups"]["dev"]
181+
assert "foo>=2.0" not in pep735_dependencies
182+
assert "bar>=1.0" in pep735_dependencies
183+
poetry_dependencies = pyproject["tool"]["poetry"]["group"]["dev"]["dependencies"]
184+
assert "foo" not in poetry_dependencies
185+
assert "bar" in poetry_dependencies
186+
187+
expected_pep735_string = """\
188+
[dependency-groups]
189+
dev = [
190+
"bar>=1.0",
191+
]
192+
"""
193+
expected_poetry_string = """\
194+
195+
[tool.poetry.group.dev.dependencies]
196+
bar = "^1.0.0"
197+
198+
"""
199+
pyproject = cast("TOMLDocument", pyproject)
200+
string_content = pyproject.as_string()
201+
if "\r\n" in string_content:
202+
# consistent line endings
203+
expected_pep735_string = expected_pep735_string.replace("\n", "\r\n")
204+
expected_poetry_string = expected_poetry_string.replace("\n", "\r\n")
205+
206+
assert expected_pep735_string in string_content
207+
assert expected_poetry_string in string_content
208+
209+
132210
@pytest.mark.parametrize("pep_735", [True, False])
133211
def test_remove_without_specific_group_removes_from_all_groups(
134212
pep_735: bool,

0 commit comments

Comments
 (0)