Skip to content

Commit

Permalink
Check dependency versions for package files installed using `whl2cond…
Browse files Browse the repository at this point in the history
…a install`

This incorporates conda's version spec source (#116)
  • Loading branch information
analog-cbarber committed Jan 8, 2024
1 parent 69d57a4 commit cfd28e3
Show file tree
Hide file tree
Showing 6 changed files with 792 additions and 14 deletions.
11 changes: 10 additions & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2023 Christopher Barber
Copyright 2023-2024 Christopher Barber

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -199,3 +199,12 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

## Additional licenses

This source code incorporates some code taken from other projects
with compatible licenses, specifically:

* https://github.com/conda/conda/blob/main/conda/models/version.py (BSD-3)


6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ module = [
]
ignore_missing_imports = true

[tool.pylint.main]
ignore-paths=['^src/whl2conda/external/.*$']

[tool.pylint.build_main]
jobs = 0 # enable parallel checks
py-version = "3.8" # min python version
Expand Down Expand Up @@ -121,6 +124,9 @@ disable = [

[tool.ruff]
line-length = 88
exclude = [
"src/whl2conda/external"
]

[tool.ruff.format]
line-ending = "lf"
Expand Down
42 changes: 31 additions & 11 deletions src/whl2conda/cli/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
import tempfile
from dataclasses import dataclass
from pathlib import Path
from typing import Optional, Sequence
from typing import NamedTuple, Optional, Sequence

from conda_package_handling.api import extract as extract_conda_pkg

from .common import dedent, existing_path, add_markdown_help, get_conda_bld_path
from ..external.version import ver_eval

__all__ = ["install_main"]

Expand Down Expand Up @@ -62,6 +63,14 @@ def parse(
return cls(**vars(ns))


class InstallFileInfo(NamedTuple):
"""Holds information about a conda file to be installed"""

path: Path
name: str
version: str


# pylint: disable=too-many-locals
def install_main(
args: Optional[Sequence[str]] = None,
Expand Down Expand Up @@ -188,9 +197,7 @@ def install_main(

subdir = "noarch"
dependencies: list[str] = []
file_specs: list[
tuple[str, str]
] = [] # name/version pairs of package files being installed
file_specs: list[InstallFileInfo] = []

for conda_file in conda_files:
conda_fname = str(conda_file.name)
Expand All @@ -209,7 +216,9 @@ def install_main(
subdir = index["subdir"]
package_name = index["name"]
package_version = index.get("version", "")
file_specs.append((package_name, package_version))
file_specs.append(
InstallFileInfo(conda_file, package_name, package_version)
)
dependencies.extend(index.get("depends", []))
except Exception as ex: # pylint: disable=broad-exception-caught
parser.error(f"Cannot extract conda package '{conda_file}:\n{ex}'")
Expand All @@ -218,7 +227,10 @@ def install_main(
# Install into conda-bld dir
conda_bld_install(parsed, subdir)
else:
dependencies = _prune_dependencies(dependencies, file_specs)
try:
dependencies = _prune_dependencies(dependencies, file_specs)
except Exception as ex: # pylint: disable=broad-exception-caught
parser.error(str(ex))
conda_env_install(parsed, dependencies)


Expand Down Expand Up @@ -301,7 +313,7 @@ def conda_env_install(parsed: InstallArgs, dependencies: list[str]):


def _prune_dependencies(
dependencies: list[str], file_specs: list[tuple[str, str]]
dependencies: list[str], file_specs: list[InstallFileInfo]
) -> list[str]:
"""
Prunes dependencies list according to arguments
Expand All @@ -312,13 +324,18 @@ def _prune_dependencies(
Arguments:
dependencies: input list of conda dependency strings (package and optional version match specifier)
file_specs: list of package name/version tuple for packages being installed from file
file_specs: list of information on package files being installed
Returns:
List of pruned dependencies.
Raises:
ValueError if a dependency for a package file in file_specs does not match
"""

exclude_packages: dict[str, str] = dict(file_specs)
exclude_packages: dict[str, InstallFileInfo] = {
spec.name: spec for spec in file_specs
}
deps: set[str] = set()

for dep in dependencies:
Expand All @@ -327,8 +344,11 @@ def _prune_dependencies(
version = m.group("version")
if version:
version = version.replace(" ", "") # remove spaces from version spec
if name in exclude_packages:
# TODO check version and warn or error if not match dependency
if exclude := exclude_packages.get(name):
if not ver_eval(exclude.version, version):
raise ValueError(
f"{exclude.path} does not match dependency '{dep}'"
)
continue
dep = name
if version:
Expand Down
17 changes: 17 additions & 0 deletions src/whl2conda/external/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 Christopher Barber
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""
Code copied from external projects
"""
Loading

0 comments on commit cfd28e3

Please sign in to comment.