Skip to content

Commit 4d362cb

Browse files
committed
make complex marker unions and intersections deterministic
1 parent 31370a9 commit 4d362cb

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

src/poetry/core/version/markers.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -734,16 +734,16 @@ def union_simplify(self, other: BaseMarker) -> BaseMarker | None:
734734
if not shared_markers:
735735
return None
736736

737-
unique_markers = our_markers - their_markers
738-
other_unique_markers = their_markers - our_markers
737+
# Do not use sets to create MarkerUnions for deterministic order!
738+
unique_markers = (m for m in self.markers if m not in their_markers)
739+
other_unique_markers = (m for m in other.markers if m not in our_markers)
739740
unique_union = MultiMarker(*unique_markers).union(
740741
MultiMarker(*other_unique_markers)
741742
)
742743
if isinstance(unique_union, (SingleMarkerLike, AnyMarker)):
743-
# Use list instead of set for deterministic order.
744-
common_markers = [
744+
common_markers = (
745745
marker for marker in self.markers if marker in shared_markers
746-
]
746+
)
747747
return unique_union.intersect(MultiMarker(*common_markers))
748748

749749
return None
@@ -908,16 +908,16 @@ def intersect_simplify(self, other: BaseMarker) -> BaseMarker | None:
908908
if not shared_markers:
909909
return None
910910

911-
unique_markers = our_markers - their_markers
912-
other_unique_markers = their_markers - our_markers
911+
# Do not use sets to create MarkerUnions for deterministic order!
912+
unique_markers = (m for m in self.markers if m not in their_markers)
913+
other_unique_markers = (m for m in other.markers if m not in our_markers)
913914
unique_intersection = MarkerUnion(*unique_markers).intersect(
914915
MarkerUnion(*other_unique_markers)
915916
)
916917
if isinstance(unique_intersection, (SingleMarkerLike, EmptyMarker)):
917-
# Use list instead of set for deterministic order.
918-
common_markers = [
918+
common_markers = (
919919
marker for marker in self.markers if marker in shared_markers
920-
]
920+
)
921921
return unique_intersection.union(MarkerUnion(*common_markers))
922922

923923
return None

tests/version/test_markers.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,6 +2154,35 @@ def test_complex_intersection() -> None:
21542154
)
21552155

21562156

2157+
def test_complex_union_is_deterministic() -> None:
2158+
"""
2159+
This test might fail sporadically if marker operations are not deterministic!
2160+
"""
2161+
m1 = parse_marker(
2162+
'sys_platform != "darwin" and python_version >= "3.12"'
2163+
' and platform_system != "Emscripten" and (python_version < "4.0"'
2164+
' and sys_platform == "linux" and extra == "stretch"'
2165+
' or platform_system == "Windows" or extra == "test"'
2166+
' and sys_platform == "win32")'
2167+
)
2168+
m2 = parse_marker(
2169+
'sys_platform == "linux" and python_version >= "3.12"'
2170+
' and platform_system == "Emscripten" and python_version < "4.0"'
2171+
' and extra == "stretch" or sys_platform == "win32"'
2172+
' and python_version >= "3.12" and platform_system == "Emscripten"'
2173+
' and extra == "test"'
2174+
)
2175+
assert str(m1.union(m2)) == (
2176+
'python_version >= "3.12" and platform_system == "Windows"'
2177+
' and sys_platform != "darwin" or sys_platform == "linux"'
2178+
' and python_version >= "3.12" and python_version < "4.0"'
2179+
' and extra == "stretch" or python_version >= "3.12" and python_version < "4.0"'
2180+
' and extra == "stretch" and extra == "test" and (sys_platform == "linux"'
2181+
' or sys_platform == "win32") or sys_platform == "win32"'
2182+
' and python_version >= "3.12" and extra == "test"'
2183+
)
2184+
2185+
21572186
def test_union_avoids_combinatorial_explosion() -> None:
21582187
"""
21592188
combinatorial explosion without AtomicMultiMarker and AtomicMarkerUnion

0 commit comments

Comments
 (0)