Skip to content

Commit e28b86b

Browse files
committed
Update and Add Tests for Merging Versions
1 parent 3deb301 commit e28b86b

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

conda_lock/src_parser/__init__.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -537,29 +537,43 @@ def aggregate_lock_specs(
537537
[lock_spec.dependencies for lock_spec in lock_specs]
538538
):
539539
key = (dep.manager, dep.name)
540+
new_dep = dep.copy()
540541
if key in unique_deps:
541542
prev_dep = unique_deps[key]
542543

543544
# Override existing, but merge selectors
544545
previous_selectors = prev_dep.selectors
545546
previous_selectors |= dep.selectors
546-
dep.selectors = previous_selectors
547+
new_dep.selectors = previous_selectors
547548

548-
# If bold old and new are VersionedDependency, combine versions
549+
# If bold old and new are VersionedDependency, combine version strings together
550+
# If there are conflicting versions, they will be handled by the solver
549551
if isinstance(prev_dep, VersionedDependency) and isinstance(
550552
dep, VersionedDependency
551553
):
554+
assert isinstance(new_dep, VersionedDependency)
555+
556+
# MatchSpecs are expressions in DNF form: `|` is OR and `,` is AND
552557
prev_versions = [
553-
set(sec.split(",")) for sec in prev_dep.version.split("|")
558+
set(sec.split(","))
559+
for sec in prev_dep.version.split("|")
560+
if sec != ""
561+
]
562+
new_versions = [
563+
set(sec.split(",")) for sec in dep.version.split("|") if sec != ""
554564
]
555-
new_versions = [set(sec.split(",")) for sec in dep.version.split("|")]
565+
# To AND two DNF expressions, we essentially perform the distributive law
566+
# ORing every pair of terms in the individual expressions
567+
# Ex: (AB | CD) (AC | BD) = ABAC | ABBD | CDAC | CDBC = ABC | ABD | ACD | BCD
556568
cross_versions = [
557569
prev | new for prev, new in product(prev_versions, new_versions)
558570
]
559-
final_versions = set(",".join(subset) for subset in cross_versions)
560-
dep.version = "|".join(final_versions)
571+
final_versions = set(
572+
",".join(sorted(subset, reverse=True)) for subset in cross_versions
573+
)
574+
new_dep.version = "|".join(sorted(final_versions, reverse=True))
561575

562-
unique_deps[key] = dep
576+
unique_deps[key] = new_dep
563577

564578
dependencies = list(unique_deps.values())
565579
try:

tests/test_conda_lock.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,7 @@ def test_aggregate_lock_specs_multiple_platforms():
11231123
assert actual.content_hash() == expected.content_hash()
11241124

11251125

1126-
def test_aggregate_lock_specs_override_version():
1126+
def test_aggregate_lock_specs_combine_version():
11271127
base_spec = LockSpecification(
11281128
dependencies=[_make_spec("package", "=1.0")],
11291129
channels=[Channel.from_string("conda-forge")],
@@ -1139,8 +1139,28 @@ def test_aggregate_lock_specs_override_version():
11391139
)
11401140

11411141
agg_spec = aggregate_lock_specs([base_spec, override_spec])
1142+
assert agg_spec.dependencies == [_make_spec("package", "=2.0,=1.0")]
11421143

1143-
assert agg_spec.dependencies == override_spec.dependencies
1144+
1145+
def test_aggregate_lock_specs_with_union_version():
1146+
base_spec = LockSpecification(
1147+
dependencies=[_make_spec("package", "=1.0|>2")],
1148+
channels=[Channel.from_string("conda-forge")],
1149+
platforms=["linux-64"],
1150+
sources=[Path("base.yml")],
1151+
)
1152+
1153+
override_spec = LockSpecification(
1154+
dependencies=[_make_spec("package", "=2.0,<3.0.0")],
1155+
channels=[Channel.from_string("internal"), Channel.from_string("conda-forge")],
1156+
platforms=["linux-64"],
1157+
sources=[Path("override.yml")],
1158+
)
1159+
1160+
agg_spec = aggregate_lock_specs([base_spec, override_spec])
1161+
assert agg_spec.dependencies == [
1162+
_make_spec("package", ">2,=2.0,<3.0.0|=2.0,=1.0,<3.0.0")
1163+
]
11441164

11451165

11461166
def test_aggregate_lock_specs_invalid_channels():

0 commit comments

Comments
 (0)