Skip to content

Commit 9dfa8ba

Browse files
committed
union, intersect, allows_any, allows_all logic
1 parent 7ee3054 commit 9dfa8ba

File tree

2 files changed

+239
-106
lines changed

2 files changed

+239
-106
lines changed

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

Lines changed: 104 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import operator
44

5-
from typing import Any
65
from typing import Callable
76
from typing import ClassVar
87

@@ -11,7 +10,7 @@
1110
from poetry.core.constraints.generic.empty_constraint import EmptyConstraint
1211

1312

14-
OperatorType = Callable[[object, object], Any]
13+
OperatorType = Callable[[object, object], bool]
1514

1615

1716
def contains(a: object, b: object, /) -> bool:
@@ -67,57 +66,22 @@ def operator(self) -> str:
6766
return self._operator
6867

6968
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-
"""
80-
81-
if not isinstance(other, Constraint) or other.operator not in {
82-
"==",
83-
"in",
84-
"not in",
85-
}:
69+
if not isinstance(other, Constraint) or other.operator != "==":
8670
raise ValueError(
8771
f"Invalid argument for allows"
8872
f' ("other" must be a constraint with operator "=="): {other}'
8973
)
9074

91-
is_equal_op = self._operator == "=="
92-
is_non_equal_op = self._operator == "!="
93-
is_other_equal_op = other.operator == "=="
94-
is_other_non_equal_op = other.operator == "!="
95-
is_in_op = self._operator == "in"
96-
is_not_in_op = self._operator == "not in"
97-
is_other_in_op = other.operator == "in"
98-
is_other_not_in_op = other.operator == "not in"
99-
100-
if is_equal_op:
75+
if self._operator == "==":
10176
return self._value == other.value
10277

103-
if is_in_op and is_other_in_op or is_in_op and is_other_equal_op:
78+
if self._operator == "in":
10479
return bool(self._trans_op_str["in"](other.value, self._value))
10580

106-
if is_non_equal_op and not (is_other_in_op or is_other_not_in_op):
81+
if self._operator == "!=":
10782
return self._value != other.value
10883

109-
if (
110-
is_in_op
111-
and is_other_non_equal_op
112-
or is_in_op
113-
and is_other_not_in_op
114-
or is_not_in_op
115-
and is_other_non_equal_op
116-
or is_not_in_op
117-
and is_other_equal_op
118-
or is_non_equal_op
119-
and is_other_not_in_op
120-
):
84+
if self._operator == "not in":
12185
return bool(self._trans_op_str["not in"](other.value, self._value))
12286

12387
return False
@@ -127,9 +91,22 @@ def allows_all(self, other: BaseConstraint) -> bool:
12791
from poetry.core.constraints.generic import UnionConstraint
12892

12993
if isinstance(other, Constraint):
130-
if other.operator == "==":
94+
is_in_op = self._operator == "in"
95+
is_not_in_op = self._operator == "not in"
96+
97+
is_other_equal_op = other.operator == "=="
98+
is_other_in_op = other.operator == "in"
99+
is_other_not_in_op = other.operator == "not in"
100+
101+
if is_other_equal_op:
131102
return self.allows(other)
132103

104+
if is_other_in_op and is_in_op:
105+
return self._op(self.value, other.value)
106+
107+
if is_other_not_in_op and not is_not_in_op:
108+
return self._trans_op_str["not in"](other.value, self.value)
109+
133110
return self == other
134111

135112
if isinstance(other, MultiConstraint):
@@ -146,21 +123,32 @@ def allows_any(self, other: BaseConstraint) -> bool:
146123

147124
is_equal_op = self._operator == "=="
148125
is_non_equal_op = self._operator == "!="
126+
is_in_op = self._operator == "in"
127+
is_not_in_op = self._operator == "not in"
149128

150129
if is_equal_op:
151130
return other.allows(self)
152131

153132
if isinstance(other, Constraint):
154133
is_other_equal_op = other.operator == "=="
155134
is_other_non_equal_op = other.operator == "!="
135+
is_other_in_op = other.operator == "in"
136+
is_other_not_in_op = other.operator == "not in"
156137

157138
if is_other_equal_op:
158139
return self.allows(other)
159140

160141
if is_equal_op and is_other_non_equal_op:
161142
return self._value != other.value
162143

163-
return is_non_equal_op and is_other_non_equal_op
144+
return (
145+
is_in_op
146+
and is_other_in_op
147+
or is_not_in_op
148+
and is_other_not_in_op
149+
or is_non_equal_op
150+
and other.operator in {"!=", "in", "not in"}
151+
)
164152

165153
elif isinstance(other, MultiConstraint):
166154
return is_non_equal_op
@@ -188,23 +176,51 @@ def intersect(self, other: BaseConstraint) -> BaseConstraint:
188176
if other == self:
189177
return self
190178

191-
if (
192-
self.operator in {"!=", "not in", "in"}
193-
and other.operator in {"==", "in", "not in"}
194-
and self.allows(other)
195-
):
179+
if self.operator == "!=" and other.operator == "==" and self.allows(other):
196180
return other
197181

198-
if (
199-
other.operator in {"!=", "not in", "in"}
200-
and self.operator in {"==", "in", "not in"}
201-
and other.allows(self)
202-
):
182+
if other.operator == "!=" and self.operator == "==" and other.allows(self):
203183
return self
204184

205-
if other.operator in {"!=", "not in"} and self.operator in {"!=", "not in"}:
185+
if (
186+
other.operator == "!="
187+
and self.operator == "!="
188+
or self.operator == "not in"
189+
and other.operator == "not in"
190+
):
206191
return MultiConstraint(self, other)
207192

193+
other_in_self = self._trans_op_str["in"](self.value, other.value)
194+
self_in_other = self._trans_op_str["in"](other.value, self.value)
195+
is_in_op = self._operator == "in"
196+
is_other_in_op = other.operator == "in"
197+
198+
if is_in_op or other.operator == "not in":
199+
# If self is a subset of other, return self
200+
if is_other_in_op and other_in_self:
201+
return self
202+
# If neither are subsets of each other then its a MC
203+
if (is_other_in_op and not self_in_other) or (
204+
other.operator == "!=" and self_in_other
205+
):
206+
return MultiConstraint(self, other)
207+
# if it allows any of other, return other
208+
if self.allows_any(other):
209+
return other
210+
211+
if is_other_in_op or self.operator == "not in":
212+
# If other is a subset of self, return other
213+
if is_in_op and self_in_other:
214+
return other
215+
# If neither are subsets of each other then its a MC
216+
if (is_in_op and not other_in_self) or (
217+
self.operator == "!=" and other_in_self
218+
):
219+
return MultiConstraint(self, other)
220+
# if other allows any of self, return self
221+
if other.allows_any(self):
222+
return self
223+
208224
return EmptyConstraint()
209225

210226
return other.intersect(self)
@@ -216,21 +232,45 @@ def union(self, other: BaseConstraint) -> BaseConstraint:
216232
if other == self:
217233
return self
218234

219-
if (
220-
self.operator in {"!=", "not in", "in"}
221-
and other.operator in {"==", "in", "not in"}
222-
) and self.allows(other):
235+
if self.operator == "!=" and other.operator == "==" and self.allows(other):
223236
return self
224237

225-
if (
226-
other.operator in {"!=", "not in", "in"}
227-
and self.operator in {"==", "in", "not in"}
228-
) and other.allows(self):
238+
if other.operator == "!=" and self.operator == "==" and other.allows(self):
229239
return other
230240

231-
if other.operator in {"==", "in"} and self.operator in {"==", "in"}:
241+
if (
242+
other.operator == "=="
243+
and self.operator == "=="
244+
or self.operator == "not in"
245+
and other.operator == "not in"
246+
):
232247
return UnionConstraint(self, other)
233248

249+
other_in_self = self._trans_op_str["in"](self.value, other.value)
250+
self_in_other = self._trans_op_str["in"](other.value, self.value)
251+
is_in_op = self._operator == "in"
252+
is_other_in_op = other.operator == "in"
253+
254+
if is_in_op or other.operator == "not in":
255+
if is_other_in_op and self_in_other:
256+
return self
257+
if (is_other_in_op and not other_in_self) or (
258+
other.operator == "!=" and other_in_self
259+
):
260+
return UnionConstraint(self, other)
261+
if other.allows_all(self):
262+
return other
263+
264+
if is_other_in_op or self._operator == "not in":
265+
if is_in_op and other_in_self:
266+
return other
267+
if (is_in_op and not self_in_other) or (
268+
self.operator == "!=" and self_in_other
269+
):
270+
return UnionConstraint(self, other)
271+
if self.allows_all(other):
272+
return self
273+
234274
return AnyConstraint()
235275

236276
# to preserve order (functionally not necessary)

0 commit comments

Comments
 (0)