Skip to content

Commit 94be7d4

Browse files
committed
Allows, intersect, union methods updates
1 parent 336e2c2 commit 94be7d4

File tree

5 files changed

+113
-41
lines changed

5 files changed

+113
-41
lines changed

src/poetry/core/constraints/generic/constraint.py

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,43 @@ def operator(self) -> str:
6767
return self._operator
6868

6969
def allows(self, other: BaseConstraint) -> bool:
70+
"""Logic table to help
71+
72+
|| != | == | in | not in
73+
--------||--------|--------|--------|--------
74+
!= || != | != | not in | not in
75+
== || != | == | in | not in
76+
in || not in | in | in | not in
77+
not in || not in | not in | not in | false
78+
79+
"""
7080
if not isinstance(other, Constraint):
7181
raise ValueError("Unimplemented comparison of constraints")
7282

7383
is_equal_op = self._operator == "=="
7484
is_non_equal_op = self._operator == "!="
7585
is_other_equal_op = other.operator == "=="
7686
is_other_non_equal_op = other.operator == "!="
87+
is_in_op = self._operator == "in"
88+
is_not_in_op = self._operator == "not in"
89+
is_other_in_op = other.operator == "in"
90+
is_other_not_in_op = other.operator == "not in"
7791

7892
if is_equal_op and is_other_equal_op:
7993
return self._value == other.value
8094

95+
if (
96+
is_in_op
97+
and is_other_in_op
98+
or is_in_op
99+
and is_equal_op
100+
or is_equal_op
101+
and is_other_in_op
102+
or is_in_op
103+
and is_other_equal_op
104+
):
105+
return bool(self._trans_op_str["in"](other.value, self._value))
106+
81107
if (
82108
is_equal_op
83109
and is_other_non_equal_op
@@ -88,8 +114,21 @@ def allows(self, other: BaseConstraint) -> bool:
88114
):
89115
return self._value != other.value
90116

91-
if self._operator in {"in", "not in"} and other.operator == "==":
92-
return bool(self._trans_op_str[self._operator](other.value, self._value))
117+
if (
118+
is_in_op
119+
and is_other_non_equal_op
120+
or is_in_op
121+
and is_other_not_in_op
122+
or is_not_in_op
123+
and is_other_non_equal_op
124+
or is_not_in_op
125+
and is_other_equal_op
126+
or is_not_in_op
127+
and is_other_in_op
128+
or is_non_equal_op
129+
and is_other_not_in_op
130+
):
131+
return bool(self._trans_op_str["not in"](other.value, self._value))
93132

94133
return False
95134

@@ -126,20 +165,20 @@ def intersect(self, other: BaseConstraint) -> BaseConstraint:
126165
return self
127166

128167
if (
129-
(self.operator == "!=" and other.operator == "==")
130-
or (self.operator == "not in" and other.operator == "in")
131-
) and self.allows(other):
168+
self.operator in {"!=", "not in", "in"}
169+
and other.operator in {"==", "in", "not in"}
170+
and self.allows(other)
171+
):
132172
return other
133173

134174
if (
135-
(other.operator == "!=" and self.operator == "==")
136-
or (other.operator == "not in" and self.operator == "in")
137-
) and other.allows(self):
175+
other.operator in {"!=", "not in", "in"}
176+
and self.operator in {"==", "in", "not in"}
177+
and other.allows(self)
178+
):
138179
return self
139180

140-
if (other.operator == "!=" and self.operator == "!=") or (
141-
other.operator == "not in" and self.operator == "not in"
142-
):
181+
if other.operator in {"!=", "not in"} and self.operator in {"!=", "not in"}:
143182
return MultiConstraint(self, other)
144183

145184
return EmptyConstraint()
@@ -154,20 +193,18 @@ def union(self, other: BaseConstraint) -> BaseConstraint:
154193
return self
155194

156195
if (
157-
(self.operator == "!=" and other.operator == "==")
158-
or (self.operator == "not in" and other.operator == "in")
196+
self.operator in {"!=", "not in", "in"}
197+
and other.operator in {"==", "in", "not in"}
159198
) and self.allows(other):
160199
return self
161200

162201
if (
163-
(other.operator == "!=" and self.operator == "==")
164-
or (other.operator == "not in" and self.operator == "in")
202+
other.operator in {"!=", "not in", "in"}
203+
and self.operator in {"==", "in", "not in"}
165204
) and other.allows(self):
166205
return other
167206

168-
if (other.operator == "==" and self.operator == "==") or (
169-
other.operator == "in" and self.operator == "in"
170-
):
207+
if other.operator in {"==", "in"} and self.operator in {"==", "in"}:
171208
return UnionConstraint(self, other)
172209

173210
return AnyConstraint()
@@ -194,5 +231,6 @@ def __hash__(self) -> int:
194231
return hash((self._operator, self._value))
195232

196233
def __str__(self) -> str:
234+
space = " " if self._operator in {"in", "not in"} else ""
197235
op = self._operator if self._operator != "==" else ""
198-
return f"{op}{self._value}"
236+
return f"{op}{space}{self._value}"

src/poetry/core/version/markers.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ def __init__(
325325
self,
326326
name: str,
327327
constraint: str | BaseConstraint | VersionConstraint,
328-
str_cmp: bool = False,
328+
swapped_name_value: bool = False,
329329
) -> None:
330330
from poetry.core.constraints.generic import (
331331
parse_constraint as parse_generic_constraint,
@@ -335,7 +335,7 @@ def __init__(
335335
parsed_constraint: BaseConstraint | VersionConstraint
336336
parser: Callable[[str], BaseConstraint | VersionConstraint]
337337
original_constraint_string = constraint_string = str(constraint)
338-
self._str_cmp: bool = str_cmp
338+
self._swapped_name_value: bool = swapped_name_value
339339

340340
# Extract operator and value
341341
m = self._CONSTRAINT_RE.match(constraint_string)
@@ -353,7 +353,7 @@ def __init__(
353353
# when string comparison flag is set. We let
354354
# the generic constraint parser handle it and
355355
# fixup the constraint object after
356-
if name == "platform_release" and str_cmp:
356+
if name == "platform_release" and swapped_name_value:
357357
pass
358358
elif name in self._VERSION_LIKE_MARKER_NAME:
359359
parser = parse_marker_version_constraint
@@ -390,15 +390,6 @@ def __init__(
390390
f"Invalid marker for '{name}': {original_constraint_string}"
391391
) from e
392392

393-
# This is a fixup on constraint if its a string like
394-
# comparison for platform_release
395-
if (
396-
self._operator in {"in", "not in"}
397-
and self._str_cmp
398-
and isinstance(parsed_constraint, Constraint)
399-
):
400-
parsed_constraint = Constraint(self._value, self._operator)
401-
402393
super().__init__(name, parsed_constraint)
403394

404395
@property
@@ -456,9 +447,10 @@ def invert(self) -> BaseMarker:
456447
# We should never go there
457448
raise RuntimeError(f"Invalid marker operator '{self._operator}'")
458449

459-
constraint = f"{self._name} {operator} '{self._value}'"
460-
if self._str_cmp:
450+
if self._swapped_name_value:
461451
constraint = f'"{self._value}" {operator} {self._name}'
452+
else:
453+
constraint = f"{self._name} {operator} '{self._value}'"
462454
return parse_marker(constraint)
463455

464456
def __eq__(self, other: object) -> bool:
@@ -471,7 +463,7 @@ def __hash__(self) -> int:
471463
return hash(self._key)
472464

473465
def __str__(self) -> str:
474-
if self._str_cmp:
466+
if self._swapped_name_value:
475467
return f'"{self._value}" {self._operator} {self._name}'
476468
return f'{self._name} {self._operator} "{self._value}"'
477469

@@ -918,12 +910,14 @@ def _compact_markers(
918910

919911
elif token.data == f"{tree_prefix}item":
920912
name, op, value = token.children
921-
str_cmp = value.type == f"{tree_prefix}MARKER_NAME"
922-
if str_cmp:
913+
swapped_name_value = value.type == f"{tree_prefix}MARKER_NAME"
914+
if swapped_name_value:
923915
name, value = value, name
924916

925917
value = value[1:-1]
926-
sub_marker = SingleMarker(str(name), f"{op}{value}", str_cmp=str_cmp)
918+
sub_marker = SingleMarker(
919+
str(name), f"{op}{value}", swapped_name_value=swapped_name_value
920+
)
927921
groups[-1].append(sub_marker)
928922

929923
elif token.data == f"{tree_prefix}BOOL_OP" and token.children[0] == "or":

tests/constraints/generic/test_constraint.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,26 @@ def test_invert(constraint: BaseConstraint, inverted: BaseConstraint) -> None:
285285
Constraint("tegra", "not in"), Constraint("rpi-v8", "not in")
286286
),
287287
),
288+
(
289+
Constraint("5.10.123-tegra", "!="),
290+
Constraint("tegra", "not in"),
291+
Constraint("tegra", "not in"),
292+
),
293+
(
294+
Constraint("5.10.123-tegra", "!="),
295+
Constraint("tegra", "in"),
296+
EmptyConstraint(),
297+
),
298+
(
299+
Constraint("5.10.123-tegra", "=="),
300+
Constraint("tegra", "in"),
301+
Constraint("5.10.123-tegra"),
302+
),
303+
(
304+
Constraint("5.10.123", "=="),
305+
Constraint("tegra", "in"),
306+
EmptyConstraint(),
307+
),
288308
],
289309
)
290310
def test_intersect(
@@ -500,6 +520,21 @@ def test_intersect(
500520
Constraint("tegra", "not in"),
501521
AnyConstraint(),
502522
),
523+
(
524+
Constraint("5.10.123-tegra", "!="),
525+
Constraint("tegra", "in"),
526+
AnyConstraint(),
527+
),
528+
(
529+
Constraint("5.10.123", "!="),
530+
Constraint("tegra", "in"),
531+
AnyConstraint(),
532+
),
533+
(
534+
Constraint("5.10.123-tegra", "!="),
535+
Constraint("tegra", "not in"),
536+
Constraint("5.10.123-tegra", "!="),
537+
),
503538
],
504539
)
505540
def test_union(

tests/constraints/generic/test_main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_parse_constraint(input: str, constraint: AnyConstraint | Constraint) ->
4242
),
4343
),
4444
(
45-
"not integra,not inrpi-v8",
45+
"not in tegra,not in rpi-v8",
4646
MultiConstraint(
4747
Constraint("tegra", "not in"),
4848
Constraint("rpi-v8", "not in"),
@@ -63,7 +63,7 @@ def test_parse_constraint_multi(input: str, constraint: MultiConstraint) -> None
6363
UnionConstraint(Constraint("win32"), Constraint("linux2", "!=")),
6464
),
6565
(
66-
"integra || inrpi-v8",
66+
"in tegra || in rpi-v8",
6767
UnionConstraint(Constraint("tegra", "in"), Constraint("rpi-v8", "in")),
6868
),
6969
],

tests/version/test_markers.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ def test_parse_marker(marker: str) -> None:
114114
"platform_machine",
115115
"!=aarch64, !=loongarch64",
116116
),
117-
('"tegra" not in platform_release', "platform_release", "not integra"),
118-
('"rpi-v8" in platform_release', "platform_release", "inrpi-v8"),
117+
('"tegra" not in platform_release', "platform_release", "not in tegra"),
118+
('"rpi-v8" in platform_release', "platform_release", "in rpi-v8"),
119119
],
120120
)
121121
def test_parse_single_marker(
@@ -978,6 +978,11 @@ def test_multi_marker_removes_duplicates() -> None:
978978
{"platform_release": "4.9.254-tegra"},
979979
True,
980980
),
981+
(
982+
"platform_release != '4.9.253-tegra'",
983+
{"platform_release": "4.9.253"},
984+
True,
985+
),
981986
(
982987
"platform_release >= '6.6.0+rpt-rpi-v8'",
983988
{"platform_release": "6.6.20+rpt-rpi-v8"},

0 commit comments

Comments
 (0)