Spec.satisfies should be commutative when strict=False (#35598)
The call: ``` x.satisfies(y[, strict=False]) ``` is commutative, and tests non-empty intersection, whereas: ``` x.satsifies(y, strict=True) ``` is not commutative, and tests set-inclusion. There are 2 fast paths. When strict=False both self and other need to be concrete, when strict=True we can optimize when other is concrete.
This commit is contained in:
parent
33bf1fd033
commit
bc24a8f290
@ -3451,25 +3451,38 @@ def _autospec(self, spec_like):
|
|||||||
return spec_like
|
return spec_like
|
||||||
return Spec(spec_like)
|
return Spec(spec_like)
|
||||||
|
|
||||||
def satisfies(self, other, deps=True, strict=False, strict_deps=False):
|
def satisfies(self, other, deps=True, strict=False):
|
||||||
"""Determine if this spec satisfies all constraints of another.
|
"""Determine if this spec satisfies all constraints of another.
|
||||||
|
|
||||||
There are two senses for satisfies:
|
There are two senses for satisfies, depending on the ``strict``
|
||||||
|
argument.
|
||||||
|
|
||||||
* `loose` (default): the absence of a constraint in self
|
* ``strict=False``: the left-hand side and right-hand side have
|
||||||
implies that it *could* be satisfied by other, so we only
|
non-empty intersection. For example ``zlib`` satisfies
|
||||||
check that there are no conflicts with other for
|
``zlib@1.2.3`` and ``zlib@1.2.3`` satisfies ``zlib``. In this
|
||||||
constraints that this spec actually has.
|
sense satisfies is a commutative operation: ``x.satisfies(y)``
|
||||||
|
if and only if ``y.satisfies(x)``.
|
||||||
|
|
||||||
* `strict`: strict means that we *must* meet all the
|
* ``strict=True``: the left-hand side is a subset of the right-hand
|
||||||
constraints specified on other.
|
side. For example ``zlib@1.2.3`` satisfies ``zlib``, but ``zlib``
|
||||||
|
does not satisfy ``zlib@1.2.3``. In this sense satisfies is not
|
||||||
|
commutative: the left-hand side should be at least as constrained
|
||||||
|
as the right-hand side.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
other = self._autospec(other)
|
other = self._autospec(other)
|
||||||
|
|
||||||
# The only way to satisfy a concrete spec is to match its hash exactly.
|
# Optimizations for right-hand side concrete:
|
||||||
|
# 1. For subset (strict=True) tests this means the left-hand side must
|
||||||
|
# be the same singleton with identical hash. Notice that package hashes
|
||||||
|
# can be different for otherwise indistinguishable concrete Spec objects.
|
||||||
|
# 2. For non-empty intersection (strict=False) we only have a fast path
|
||||||
|
# when the left-hand side is also concrete.
|
||||||
if other.concrete:
|
if other.concrete:
|
||||||
return self.concrete and self.dag_hash() == other.dag_hash()
|
if strict:
|
||||||
|
return self.concrete and self.dag_hash() == other.dag_hash()
|
||||||
|
elif self.concrete:
|
||||||
|
return self.dag_hash() == other.dag_hash()
|
||||||
|
|
||||||
# If the names are different, we need to consider virtuals
|
# If the names are different, we need to consider virtuals
|
||||||
if self.name != other.name and self.name and other.name:
|
if self.name != other.name and self.name and other.name:
|
||||||
|
@ -1293,3 +1293,16 @@ def test_package_hash_affects_dunder_and_dag_hash(mock_packages, default_mock_co
|
|||||||
assert hash(a1) != hash(a2)
|
assert hash(a1) != hash(a2)
|
||||||
assert a1.dag_hash() != a2.dag_hash()
|
assert a1.dag_hash() != a2.dag_hash()
|
||||||
assert a1.process_hash() != a2.process_hash()
|
assert a1.process_hash() != a2.process_hash()
|
||||||
|
|
||||||
|
|
||||||
|
def test_satisfies_is_commutative_with_concrete_specs(mock_packages, default_mock_concretization):
|
||||||
|
a1 = default_mock_concretization("a@1.0")
|
||||||
|
a2 = Spec("a@1.0")
|
||||||
|
|
||||||
|
# strict=False means non-empty intersection, which is commutative.
|
||||||
|
assert a1.satisfies(a2)
|
||||||
|
assert a2.satisfies(a1)
|
||||||
|
|
||||||
|
# strict=True means set inclusion, which is not commutative.
|
||||||
|
assert a1.satisfies(a2, strict=True)
|
||||||
|
assert not a2.satisfies(a1, strict=True)
|
||||||
|
Loading…
Reference in New Issue
Block a user