Skip to content

Commit

Permalink
Merge pull request #663 from maresb/split-virtual-package-from-lockspec
Browse files Browse the repository at this point in the history
Split virtual-package repo from LockSpecification
  • Loading branch information
maresb authored Sep 7, 2024
2 parents 9026d25 + 2d86747 commit 1d33e10
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 115 deletions.
78 changes: 40 additions & 38 deletions conda_lock/conda_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
from conda_lock.pypi_solver import solve_pypi
from conda_lock.src_parser import make_lock_spec
from conda_lock.virtual_package import (
FakeRepoData,
default_virtual_package_repodata,
virtual_package_repo_from_specification,
)
Expand Down Expand Up @@ -312,6 +313,30 @@ def make_lock_files( # noqa: C901
YAML or JSON file(s) containing structured metadata to add to metadata section of the lockfile.
"""

# Compute lock specification
required_categories = {"main"}
if include_dev_dependencies:
required_categories.add("dev")
if extras is not None:
required_categories.update(extras)
lock_spec = make_lock_spec(
src_files=src_files,
channel_overrides=channel_overrides,
platform_overrides=platform_overrides,
required_categories=required_categories if filter_categories else None,
)

# Load existing lockfile if it exists
original_lock_content: Optional[Lockfile] = None
if lockfile_path.exists():
try:
original_lock_content = parse_conda_lock_file(lockfile_path)
except (yaml.error.YAMLError, FileNotFoundError):
logger.warning("Failed to parse existing lock. Regenerating from scratch")
original_lock_content = None
else:
original_lock_content = None

# initialize virtual packages
if virtual_package_spec and virtual_package_spec.exists():
virtual_package_repo = virtual_package_repo_from_specification(
Expand All @@ -324,38 +349,9 @@ def make_lock_files( # noqa: C901
with_cuda = "11.4"
else:
cuda_specified = True

virtual_package_repo = default_virtual_package_repodata(cuda_version=with_cuda)

required_categories = {"main"}
if include_dev_dependencies:
required_categories.add("dev")
if extras is not None:
required_categories.update(extras)

with virtual_package_repo:
lock_spec = make_lock_spec(
src_files=src_files,
channel_overrides=channel_overrides,
platform_overrides=platform_overrides,
virtual_package_repo=virtual_package_repo,
required_categories=required_categories if filter_categories else None,
)
original_lock_content: Optional[Lockfile] = None

if lockfile_path.exists():
import yaml

try:
original_lock_content = parse_conda_lock_file(lockfile_path)
except (yaml.error.YAMLError, FileNotFoundError):
logger.warning(
"Failed to parse existing lock. Regenerating from scratch"
)
original_lock_content = None
else:
original_lock_content = None

platforms_to_lock: List[str] = []
platforms_already_locked: List[str] = []
if original_lock_content is not None:
Expand All @@ -368,7 +364,9 @@ def make_lock_files( # noqa: C901
update
or platform not in platforms_already_locked
or not check_input_hash
or lock_spec.content_hash_for_platform(platform)
or lock_spec.content_hash_for_platform(
platform, virtual_package_repo
)
!= original_lock_content.metadata.content_hash[platform]
):
platforms_to_lock.append(platform)
Expand Down Expand Up @@ -399,6 +397,7 @@ def make_lock_files( # noqa: C901
metadata_choices=metadata_choices,
metadata_yamls=metadata_yamls,
strip_auth=strip_auth,
virtual_package_repo=virtual_package_repo,
)

if not original_lock_content:
Expand Down Expand Up @@ -720,11 +719,13 @@ def sanitize_lockfile_line(line: str) -> str:


def _solve_for_arch(
*,
conda: PathLike,
spec: LockSpecification,
platform: str,
channels: List[Channel],
pip_repositories: List[PipRepository],
virtual_package_repo: FakeRepoData,
update_spec: Optional[UpdateSpecification] = None,
strip_auth: bool = False,
) -> List[LockedDependency]:
Expand Down Expand Up @@ -767,10 +768,10 @@ def _solve_for_arch(
python_version=conda_deps["python"].version,
platform=platform,
platform_virtual_packages=(
spec.virtual_package_repo.all_repodata.get(
platform, {"packages": None}
)["packages"]
if spec.virtual_package_repo
virtual_package_repo.all_repodata.get(platform, {"packages": None})[
"packages"
]
if virtual_package_repo
else None
),
pip_repositories=pip_repositories,
Expand Down Expand Up @@ -821,14 +822,13 @@ def create_lockfile_from_spec(
metadata_choices: AbstractSet[MetadataOption] = frozenset(),
metadata_yamls: Sequence[pathlib.Path] = (),
strip_auth: bool = False,
virtual_package_repo: FakeRepoData,
) -> Lockfile:
"""
Solve or update specification
"""
if platforms is None:
platforms = []
assert spec.virtual_package_repo is not None
virtual_package_channel = spec.virtual_package_repo.channel

locked: Dict[Tuple[str, str, str], LockedDependency] = {}

Expand All @@ -837,8 +837,9 @@ def create_lockfile_from_spec(
conda=conda,
spec=spec,
platform=platform,
channels=[*spec.channels, virtual_package_channel],
channels=[*spec.channels, virtual_package_repo.channel],
pip_repositories=spec.pip_repositories,
virtual_package_repo=virtual_package_repo,
update_spec=update_spec,
strip_auth=strip_auth,
)
Expand Down Expand Up @@ -888,11 +889,12 @@ def create_lockfile_from_spec(
inputs_metadata = None

custom_metadata = get_custom_metadata(metadata_yamls=metadata_yamls)
content_hash = spec.content_hash(virtual_package_repo)

return Lockfile(
package=[locked[k] for k in locked],
metadata=LockMeta(
content_hash=spec.content_hash(),
content_hash=content_hash,
channels=[c for c in spec.channels],
platforms=spec.platforms,
sources=list(meta_sources.keys()),
Expand Down
15 changes: 9 additions & 6 deletions conda_lock/models/lock_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,23 @@ class LockSpecification(BaseModel):
channels: List[Channel]
sources: List[pathlib.Path]
pip_repositories: List[PipRepository] = Field(default_factory=list)
virtual_package_repo: Optional[FakeRepoData] = None
allow_pypi_requests: bool = True

@property
def platforms(self) -> List[str]:
return list(self.dependencies.keys())

def content_hash(self) -> Dict[str, str]:
def content_hash(
self, virtual_package_repo: Optional[FakeRepoData]
) -> Dict[str, str]:
return {
platform: self.content_hash_for_platform(platform)
platform: self.content_hash_for_platform(platform, virtual_package_repo)
for platform in self.platforms
}

def content_hash_for_platform(self, platform: str) -> str:
def content_hash_for_platform(
self, platform: str, virtual_package_repo: Optional[FakeRepoData]
) -> str:
data = {
"channels": [c.json() for c in self.channels],
"specs": [
Expand All @@ -89,8 +92,8 @@ def content_hash_for_platform(self, platform: str) -> str:
}
if self.pip_repositories:
data["pip_repositories"] = [repo.json() for repo in self.pip_repositories]
if self.virtual_package_repo is not None:
vpr_data = self.virtual_package_repo.all_repodata
if virtual_package_repo is not None:
vpr_data = virtual_package_repo.all_repodata
data["virtual_package_hash"] = {
"noarch": vpr_data.get("noarch", {}),
**{platform: vpr_data.get(platform, {})},
Expand Down
2 changes: 0 additions & 2 deletions conda_lock/src_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ def _parse_source_files(
def make_lock_spec(
*,
src_files: List[pathlib.Path],
virtual_package_repo: FakeRepoData,
channel_overrides: Optional[Sequence[str]] = None,
pip_repository_overrides: Optional[Sequence[str]] = None,
platform_overrides: Optional[Sequence[str]] = None,
Expand Down Expand Up @@ -131,6 +130,5 @@ def dep_has_category(d: Dependency, categories: AbstractSet[str]) -> bool:
channels=channels,
pip_repositories=pip_repositories,
sources=aggregated_lock_spec.sources,
virtual_package_repo=virtual_package_repo,
allow_pypi_requests=aggregated_lock_spec.allow_pypi_requests,
)
Loading

0 comments on commit 1d33e10

Please sign in to comment.