Skip to content

Commit

Permalink
Merge branch 'main' into feat/460/private-pypi-environment-variable
Browse files Browse the repository at this point in the history
  • Loading branch information
jacksmith15 authored Sep 11, 2023
2 parents c2083e5 + 8a71638 commit 665e8c8
Show file tree
Hide file tree
Showing 20 changed files with 141 additions and 52 deletions.
9 changes: 7 additions & 2 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
[flake8]
# NOTE: Can ruff replace flake8? See `tool.isort`, these two configs should be
# kept in sync until we pick one.
ignore = E203, E266, E501, W503, F403, F401
per-file-ignores =
conda_lock/src_parser/meta_yaml.py:E122

max-line-length = 89
max-complexity = 18
select = B,C,E,F,W,T4,B9
max-complexity = 19
select = B,C,E,F,W,T4,B9
2 changes: 1 addition & 1 deletion .github/workflows/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
concurrency: ci-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
with:
submodules: "recursive"
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
packages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
with:
fetch-depth: 0

Expand All @@ -37,7 +37,7 @@ jobs:

- name: Publish a Python distribution to PyPI
if: ${{ github.event_name == 'release' }}
uses: pypa/[email protected].8
uses: pypa/[email protected].10
with:
user: __token__
password: ${{ secrets.PYPI_PASSWORD }}
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
FORCE_COLOR: "1"
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4

- name: Install Conda environment with Micromamba
uses: mamba-org/setup-micromamba@v1
Expand Down Expand Up @@ -73,7 +73,7 @@ jobs:
PYTHONUNBUFFERED: "1"
FORCE_COLOR: "1"
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4

- uses: mamba-org/setup-micromamba@v1
with:
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/update-lockfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ on:

jobs:
conda-lock:
# Don't run scheduled job on forks. Ref: <https://github.com/orgs/community/discussions/26684#discussioncomment-3252843>
if: (github.event_name == 'schedule' && github.repository == 'conda/conda-lock') || (github.event_name != 'schedule')
defaults:
run:
# Ensure the environment is activated
# <https://github.com/mamba-org/provision-with-micromamba#important>
shell: bash -l {0}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
- name: Install Micromamba
uses: mamba-org/setup-micromamba@v1
with:
Expand Down
21 changes: 14 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,36 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
exclude: "^.*\\.patch$"
- id: check-ast
- id: trailing-whitespace
exclude: "^.*\\.patch$"
- id: check-ast

- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
language_version: python3

- repo: https://github.com/pycqa/flake8
rev: 6.0.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.287
hooks:
- id: flake8
- id: ruff
args: [--fix, --exit-non-zero-on-fix]

# Ruff should catch (and mostly fix) everything that flake8 and isort do; if
# either of these checks fails, can Ruff's config be updated to catch the same?
- repo: https://github.com/pycqa/flake8
rev: 6.1.0
hooks:
- id: flake8
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black", "--filter-files"]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.4.1
rev: v1.5.1
hooks:
- id: mypy
additional_dependencies:
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,7 @@ and update operations. You can supply a different filename with e.g.
conda-lock --lockfile superspecial.conda-lock.yml
```

The extension `.conda-lock.yml` will be added if not present. Rendered
environment files (env or explicit) must end with `.lock` and will be named as
`"conda-{platform}.lock"` by default.
Rendered `explicit` and `env` lockfiles will be named as `"conda-{platform}.lock"` and `"conda-{platform}.lock.yml` respectively by default.

If you want to override that call conda-lock as follows.
```bash
Expand All @@ -89,7 +87,7 @@ conda-lock -k explicit --filename-template "specific-{platform}.conda.lock"
Conda-lock will build a spec list from several files if requested.

```bash
conda-lock -f base.yml -f specific.yml -p linux-64 --filename-template "specific-{platform}.lock"
conda-lock -f base.yml -f specific.yml -p linux-64 -k explicit --filename-template "specific-{platform}.lock"
````

In this case all dependencies are combined, and the ordered union of all `channels` is used as the final
Expand Down
46 changes: 37 additions & 9 deletions conda_lock/conda_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import yaml

from ensureconda.api import ensureconda
from ensureconda.resolve import platform_subdir
from typing_extensions import Literal

from conda_lock.click_helpers import OrderedGroup
Expand All @@ -54,7 +55,11 @@
determine_conda_executable,
is_micromamba,
)
from conda_lock.lockfile import parse_conda_lock_file, write_conda_lock_file
from conda_lock.lockfile import (
UnknownLockfileVersion,
parse_conda_lock_file,
write_conda_lock_file,
)
from conda_lock.lockfile.v2prelim.models import (
GitMeta,
InputMeta,
Expand Down Expand Up @@ -139,6 +144,10 @@
"""


class UnknownLockfileKind(ValueError):
pass


def _extract_platform(line: str) -> Optional[str]:
search = PLATFORM_PATTERN.search(line)
if search:
Expand Down Expand Up @@ -241,7 +250,7 @@ def fn_to_dist_name(fn: str) -> str:
return fn


def make_lock_files( # noqa: C901
def make_lock_files(
*,
conda: PathLike,
src_files: List[pathlib.Path],
Expand Down Expand Up @@ -768,7 +777,7 @@ def create_lockfile_from_spec(
*,
conda: PathLike,
spec: LockSpecification,
platforms: List[str] = [],
platforms: Optional[List[str]] = None,
lockfile_path: pathlib.Path,
update_spec: Optional[UpdateSpecification] = None,
metadata_choices: AbstractSet[MetadataOption] = frozenset(),
Expand All @@ -778,6 +787,8 @@ def create_lockfile_from_spec(
"""
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

Expand Down Expand Up @@ -930,23 +941,21 @@ def _render_lockfile_for_install(
Optional dependency groups to include in output
"""

if not filename.name.endswith(DEFAULT_LOCKFILE_NAME):
kind = _detect_lockfile_kind(pathlib.Path(filename))
if kind in ("explicit", "env"):
yield filename
return

from ensureconda.resolve import platform_subdir

lock_content = parse_conda_lock_file(pathlib.Path(filename))

platform = platform_subdir()
if platform not in lock_content.metadata.platforms:
suggested_platforms_section = "platforms:\n- "
suggested_platforms_section += "\n- ".join(
[platform] + lock_content.metadata.platforms
[platform, *lock_content.metadata.platforms]
)
suggested_platform_args = "--platform=" + " --platform=".join(
[platform] + lock_content.metadata.platforms
[platform, *lock_content.metadata.platforms]
)
raise PlatformValidationError(
f"The lockfile {filename} does not contain a solution for the current "
Expand Down Expand Up @@ -982,6 +991,25 @@ def _render_lockfile_for_install(
yield path


def _detect_lockfile_kind(path: pathlib.Path) -> TKindAll:
content = path.read_text(encoding="utf-8")
if "@EXPLICIT" in {line.strip() for line in content.splitlines()}:
return "explicit"
try:
lockfile = yaml.safe_load(content)
if {"channels", "dependencies"} <= set(lockfile):
return "env"
if "version" in lockfile:
# Version validation is handled by `lockfile.parse_conda_lock_file`
return "lock"
raise UnknownLockfileKind(f"Could not detect the kind of lockfile at {path}")
except yaml.YAMLError:
raise UnknownLockfileKind(
f"Could not detect the kind of lockfile at {path}. Note that explicit "
"lockfiles must contain the line '@EXPLICIT'."
)


def run_lock(
environment_files: List[pathlib.Path],
*,
Expand Down
2 changes: 1 addition & 1 deletion conda_lock/conda_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ def update_specs_for_arch(
proc = subprocess.run(
[
str(arg)
for arg in args + ["-p", prefix, "--json", "--dry-run", *to_update]
for arg in [*args, "-p", prefix, "--json", "--dry-run", *to_update]
],
env=conda_env_override(platform),
stdout=subprocess.PIPE,
Expand Down
12 changes: 11 additions & 1 deletion conda_lock/lockfile/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
from conda_lock.models.lock_spec import Dependency


class MissingLockfileVersion(ValueError):
pass


class UnknownLockfileVersion(ValueError):
pass


def _seperator_munge_get(
d: Mapping[str, Union[List[LockedDependency], LockedDependency]], key: str
) -> Union[List[LockedDependency], LockedDependency]:
Expand Down Expand Up @@ -135,8 +143,10 @@ def parse_conda_lock_file(path: pathlib.Path) -> Lockfile:
version = content.pop("version", None)
if version == 1:
return lockfile_v1_to_v2(LockfileV1.parse_obj(content))
elif version is None:
raise MissingLockfileVersion(f"{path} is missing a version")
else:
raise ValueError(f"{path} has unknown version {version}")
raise UnknownLockfileVersion(f"{path} has unknown version {version}")


def write_conda_lock_file(
Expand Down
3 changes: 3 additions & 0 deletions conda_lock/lockfile/v2prelim/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# isort: skip_file
# TODO: Remove the isort skip comment above if/when isort is no longer used. This skip
# exists because isort and ruff disagree about how to sort the imports in this file.
from collections import defaultdict
from typing import ClassVar, Dict, List, Optional

Expand Down
2 changes: 1 addition & 1 deletion conda_lock/models/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def _detect_used_env_var(

if value.startswith("$"):
return value.lstrip("$").strip("{}")
for suffix in preferred_env_var_suffix + [""]:
for suffix in [*preferred_env_var_suffix, ""]:
candidates = {v: k for k, v in os.environ.items() if k.upper().endswith(suffix)}
# try first with a simple match
key = candidates.get(value)
Expand Down
2 changes: 1 addition & 1 deletion conda_lock/src_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from conda_lock.virtual_package import FakeRepoData


DEFAULT_PLATFORMS = ["osx-64", "linux-64", "win-64"]
DEFAULT_PLATFORMS = ["linux-64", "osx-arm64", "osx-64", "win-64"]


logger = logging.getLogger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions conda_lock/src_parser/meta_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__( # type: ignore
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
__getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
__complex__ = __pow__ = __rpow__ = \
lambda self, *args, **kwargs: self._return_undefined(self._undefined_name) # noqa: E122
lambda self, *args, **kwargs: self._return_undefined(self._undefined_name)
# fmt: on

# Accessing an attribute of an Undefined variable
Expand All @@ -60,7 +60,7 @@ def __getattr__(self, k: str) -> "UndefinedNeverFail":

# Unlike the methods above, Python requires that these
# few methods must always return the correct type
__str__ = __repr__ = lambda self: self._return_value(str()) # type: ignore # noqa: E731
__str__ = __repr__ = lambda self: self._return_value(str()) # type: ignore
__unicode__ = lambda self: self._return_value("") # noqa: E731
__int__ = lambda self: self._return_value(0) # type: ignore # noqa: E731
__float__ = lambda self: self._return_value(0.0) # type: ignore # noqa: E731
Expand Down
3 changes: 2 additions & 1 deletion conda_lock/src_parser/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def filter_platform_selectors(
yield line
else:
logger.warning(
"filtered out line `%s` due to unmatchable selector", line
f"filtered out line `{line}` on platform {platform} due to "
f"non-matching selector `{cond}`"
)
else:
yield line
1 change: 0 additions & 1 deletion conda_lock/virtual_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class FakePackage(BaseModel):
"""A minimal representation of the required metadata for a conda package"""

class Config:
allow_mutation = False
frozen = True

name: str
Expand Down
6 changes: 0 additions & 6 deletions environments/dev-environment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,13 @@ dependencies:
- check-manifest
- doctr
- filelock
- flake8
- flake8-builtins
- flake8-comprehensions
- flake8-mutable
- python-build
- freezegun
- isort
- mypy
- pre-commit
- pylint
- pytest
- pytest-cov
- pytest-flake8
- pytest-xdist
- pytest-timeout
- tomli
Expand Down
Loading

0 comments on commit 665e8c8

Please sign in to comment.