Skip to content

Commit a336fdf

Browse files
radoeringabn
authored andcommitted
PEP 621 support: fix merging project.optional-dependencies with tool.poetry.dependencies
The extra marker of optional dependencies is usually only implicit but has to be considered when merging dependencies.
1 parent 18ce144 commit a336fdf

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed

src/poetry/core/packages/dependency_group.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
from collections import defaultdict
44
from typing import TYPE_CHECKING
55

6+
from poetry.core.version.markers import parse_marker
7+
68

79
if TYPE_CHECKING:
810
from poetry.core.packages.dependency import Dependency
911
from poetry.core.version.markers import BaseMarker
1012

11-
1213
MAIN_GROUP = "main"
1314

1415

@@ -42,9 +43,20 @@ def dependencies_for_locking(self) -> list[Dependency]:
4243
for dep in self._dependencies:
4344
if dep.name in poetry_dependencies_by_name:
4445
enriched = False
46+
dep_marker = dep.marker
47+
if dep.in_extras:
48+
dep_marker = dep.marker.intersect(
49+
parse_marker(
50+
" or ".join(
51+
f"extra == '{extra}'" for extra in dep.in_extras
52+
)
53+
)
54+
)
4555
for poetry_dep in poetry_dependencies_by_name[dep.name]:
46-
marker = dep.marker.intersect(poetry_dep.marker)
56+
marker = dep_marker.intersect(poetry_dep.marker)
4757
if not marker.is_empty():
58+
if marker == dep_marker:
59+
marker = dep.marker
4860
enriched = True
4961
dependencies.append(_enrich_dependency(dep, poetry_dep, marker))
5062
if not enriched:

tests/packages/test_dependency_group.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import pytest
66

7+
from packaging.utils import canonicalize_name
8+
79
from poetry.core.packages.dependency import Dependency
810
from poetry.core.packages.dependency_group import DependencyGroup
911
from poetry.core.packages.directory_dependency import DirectoryDependency
@@ -15,6 +17,7 @@ def create_dependency(
1517
constraint: str = "*",
1618
*,
1719
extras: tuple[str, ...] = (),
20+
in_extras: tuple[str, ...] = (),
1821
allows_prereleases: bool | None = None,
1922
develop: bool = False,
2023
source_name: str | None = None,
@@ -26,6 +29,8 @@ def create_dependency(
2629
extras=extras,
2730
allows_prereleases=allows_prereleases,
2831
)
32+
if in_extras:
33+
dep._in_extras = [canonicalize_name(extra) for extra in in_extras]
2934
if develop:
3035
dep._develop = develop
3136
if source_name:
@@ -260,6 +265,88 @@ def test_remove_dependency_removes_from_both_lists() -> None:
260265
[create_dependency("foo", source_name="src")],
261266
[create_dependency("foo", source_name="src", marker="extra == 'extra1'")],
262267
),
268+
# extras - special
269+
# root extras do not have an extra marker, they just have set _in_extras!
270+
(
271+
[
272+
Dependency.create_from_pep_508("foo;extra!='extra1'"),
273+
create_dependency("foo", in_extras=("extra1",)),
274+
],
275+
[
276+
create_dependency("foo", marker="extra!='extra1'", source_name="src1"),
277+
create_dependency("foo", marker="extra=='extra1'", source_name="src2"),
278+
],
279+
[
280+
create_dependency("foo", source_name="src1", marker="extra!='extra1'"),
281+
create_dependency("foo", source_name="src2", in_extras=("extra1",)),
282+
],
283+
),
284+
(
285+
[
286+
Dependency.create_from_pep_508(
287+
"foo;extra!='extra1' and extra!='extra2'"
288+
),
289+
create_dependency("foo", in_extras=("extra1", "extra2")),
290+
],
291+
[
292+
create_dependency(
293+
"foo",
294+
marker="extra!='extra1' and extra!='extra2'",
295+
source_name="src1",
296+
),
297+
create_dependency(
298+
"foo",
299+
marker="extra=='extra1' or extra=='extra2'",
300+
source_name="src2",
301+
),
302+
],
303+
[
304+
create_dependency(
305+
"foo",
306+
source_name="src1",
307+
marker="extra!='extra1' and extra!='extra2'",
308+
),
309+
create_dependency(
310+
"foo", source_name="src2", in_extras=("extra1", "extra2")
311+
),
312+
],
313+
),
314+
(
315+
[
316+
create_dependency(
317+
"foo", marker="extra!='extra2'", in_extras=("extra1",)
318+
),
319+
create_dependency(
320+
"foo", marker="extra!='extra1'", in_extras=("extra2",)
321+
),
322+
],
323+
[
324+
create_dependency(
325+
"foo",
326+
marker="extra!='extra2' and extra=='extra1'",
327+
source_name="src1",
328+
),
329+
create_dependency(
330+
"foo",
331+
marker="extra!='extra1' and extra=='extra2'",
332+
source_name="src2",
333+
),
334+
],
335+
[
336+
create_dependency(
337+
"foo",
338+
source_name="src1",
339+
marker="extra!='extra2'",
340+
in_extras=("extra1",),
341+
),
342+
create_dependency(
343+
"foo",
344+
source_name="src2",
345+
marker="extra!='extra1'",
346+
in_extras=("extra2",),
347+
),
348+
],
349+
),
263350
],
264351
)
265352
def test_dependencies_for_locking(
@@ -285,6 +372,9 @@ def test_dependencies_for_locking(
285372
assert [d._develop for d in group.dependencies_for_locking] == [
286373
d._develop for d in expected_dependencies
287374
]
375+
assert [d.in_extras for d in group.dependencies_for_locking] == [
376+
d.in_extras for d in expected_dependencies
377+
]
288378

289379

290380
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)