Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 41 additions & 19 deletions src/poetry/core/version/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,14 +396,15 @@ def of(cls, *markers: BaseMarker) -> BaseMarker:
old_markers = new_markers
new_markers = []
for marker in old_markers:
if marker in new_markers:
continue
if marker.is_empty():
return marker

if marker.is_any():
if marker in new_markers or marker.is_any():
continue

intersected = False

if isinstance(marker, SingleMarker):
intersected = False
for i, mark in enumerate(new_markers):
if isinstance(mark, SingleMarker) and (
mark.name == marker.name
Expand All @@ -413,27 +414,26 @@ def of(cls, *markers: BaseMarker) -> BaseMarker:
if new_marker is not None:
new_markers[i] = new_marker
intersected = True
break

elif isinstance(mark, MarkerUnion):
intersection = mark.intersect(marker)
if isinstance(intersection, SingleMarker):
new_markers[i] = intersection
elif intersection.is_empty():
return EmptyMarker()
if intersected:
continue
intersected = cls._of_marker_union_and_single_marker(
new_markers, i, mark, marker
)
if intersected:
break

elif isinstance(marker, MarkerUnion):
for mark in new_markers:
for i, mark in enumerate(new_markers):
if isinstance(mark, SingleMarker):
intersection = marker.intersect(mark)
if isinstance(intersection, SingleMarker):
marker = intersection
intersected = cls._of_marker_union_and_single_marker(
new_markers, i, marker, mark
)
if intersected:
break
elif intersection.is_empty():
return EmptyMarker()

new_markers.append(marker)
if not intersected:
new_markers.append(marker)

if any(m.is_empty() for m in new_markers) or not new_markers:
return EmptyMarker()
Expand All @@ -443,6 +443,26 @@ def of(cls, *markers: BaseMarker) -> BaseMarker:

return MultiMarker(*new_markers)

@staticmethod
def _of_marker_union_and_single_marker(
markers: list[BaseMarker],
index: int,
marker_union: MarkerUnion,
single_marker: SingleMarker,
) -> bool:
intersection = marker_union.intersect(single_marker)

if intersection.is_empty() or isinstance(intersection, SingleMarker):
markers[index] = intersection
return True

if isinstance(intersection, MultiMarker):
markers[index] = intersection.markers[0]
markers += intersection.markers[1:]
return True

return False

@property
def markers(self) -> list[BaseMarker]:
return self._markers
Expand Down Expand Up @@ -620,6 +640,9 @@ def of(cls, *markers: BaseMarker) -> BaseMarker:
old_markers = new_markers
new_markers = []
for marker in old_markers:
if marker.is_any():
return marker

if marker in new_markers or marker.is_empty():
continue

Expand All @@ -645,7 +668,6 @@ def of(cls, *markers: BaseMarker) -> BaseMarker:
break

elif isinstance(marker, MultiMarker):
included = False
for i, mark in enumerate(new_markers):
union = marker.union_simplify(mark)
if union is not None:
Expand Down
17 changes: 15 additions & 2 deletions tests/version/test_markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1304,11 +1304,24 @@ def test_single_markers_are_found_in_complex_intersection() -> None:
'python_version >= "3.6" and python_version < "4.0" and implementation_name =='
' "cpython"'
)
intersection = m1.intersect(m2)
assert (
str(intersection)
str(m1.intersect(m2))
== 'implementation_name == "cpython" and python_version == "3.6"'
)
assert (
str(m2.intersect(m1))
== 'python_version == "3.6" and implementation_name == "cpython"'
)


def test_empty_marker_is_found_in_complex_intersection() -> None:
m1 = parse_marker(
'(platform_system != "Windows" or platform_machine != "x86") and python_version'
' == "3.8"'
)
m2 = parse_marker('platform_system == "Windows" and platform_machine == "x86"')
assert m1.intersect(m2).is_empty()
assert m2.intersect(m1).is_empty()


@pytest.mark.parametrize(
Expand Down