diff --git a/conda_lock/conda_lock.py b/conda_lock/conda_lock.py index 714004909..1ba34bbe1 100644 --- a/conda_lock/conda_lock.py +++ b/conda_lock/conda_lock.py @@ -542,7 +542,7 @@ def render_lockfile_for_platform( # noqa: C901 lockfile.toposort_inplace() for p in lockfile.package: - if p.platform == platform and ((not p.optional) or (p.category in categories)): + if p.platform == platform and p.category in categories: if p.manager == "pip": pip_deps.append(p) elif p.manager == "conda": diff --git a/conda_lock/conda_solver.py b/conda_lock/conda_solver.py index 906e55d80..9036dcc03 100644 --- a/conda_lock/conda_solver.py +++ b/conda_lock/conda_solver.py @@ -24,7 +24,7 @@ conda_pkgs_dir, is_micromamba, ) -from conda_lock.lockfile import HashModel, LockedDependency, _apply_categories +from conda_lock.lockfile import HashModel, LockedDependency, apply_categories from conda_lock.models.channel import Channel from conda_lock.models.lock_spec import Dependency, VersionedDependency @@ -195,7 +195,7 @@ def normalize_url(url: str) -> str: } # propagate categories from explicit to transitive dependencies - _apply_categories( + apply_categories( requested={k: v for k, v in specs.items() if v.manager == "conda"}, planned=planned, ) diff --git a/conda_lock/lockfile/__init__.py b/conda_lock/lockfile/__init__.py index 902e828a2..760bd0380 100644 --- a/conda_lock/lockfile/__init__.py +++ b/conda_lock/lockfile/__init__.py @@ -3,7 +3,7 @@ from collections import defaultdict from textwrap import dedent -from typing import Collection, Dict, List, Mapping, Optional, Sequence, Set, Union +from typing import Any, Collection, Dict, List, Mapping, Optional, Sequence, Set, Union import yaml @@ -35,7 +35,7 @@ def _seperator_munge_get( return d[key.replace("_", "-")] -def _apply_categories( +def apply_categories( requested: Dict[str, Dependency], planned: Mapping[str, Union[List[LockedDependency], LockedDependency]], categories: Sequence[str] = ("main", "dev"), @@ -129,12 +129,9 @@ def dep_name(manager: str, dep: str) -> str: targets = [targets] for target in targets: target.category = source.category - target.optional = source.optional -def parse_conda_lock_file( - path: pathlib.Path, -) -> Lockfile: +def parse_conda_lock_file(path: pathlib.Path) -> Lockfile: if not path.exists(): raise FileNotFoundError(f"{path} not found") @@ -144,6 +141,9 @@ def parse_conda_lock_file( if not (isinstance(version, int) and version <= Lockfile.version): raise ValueError(f"{path} has unknown version {version}") + for p in content["package"]: + del p["optional"] + return Lockfile.parse_obj(content) @@ -207,13 +207,22 @@ def write_section(text: str) -> None: """ ) - yaml.dump( - { - "version": Lockfile.version, - **json.loads( - content.json(by_alias=True, exclude_unset=True, exclude_none=True) - ), - }, - stream=f, - sort_keys=False, - ) + output: Dict[str, Any] = { + "version": Lockfile.version, + "metadata": json.loads( + content.metadata.json( + by_alias=True, exclude_unset=True, exclude_none=True + ) + ), + "package": [ + { + **package.dict( + by_alias=True, exclude_unset=True, exclude_none=True + ), + "optional": (package.category != "main"), + } + for package in content.package + ], + } + + yaml.dump(output, stream=f, sort_keys=False) diff --git a/conda_lock/lockfile/models.py b/conda_lock/lockfile/models.py index ee082eb39..296a98023 100644 --- a/conda_lock/lockfile/models.py +++ b/conda_lock/lockfile/models.py @@ -44,7 +44,6 @@ class LockedDependency(StrictModel): dependencies: Dict[str, str] = {} url: str hash: HashModel - optional: bool = False category: str = "main" source: Optional[DependencySource] = None build: Optional[str] = None diff --git a/conda_lock/models/lock_spec.py b/conda_lock/models/lock_spec.py index a6ce7b889..ded75198d 100644 --- a/conda_lock/models/lock_spec.py +++ b/conda_lock/models/lock_spec.py @@ -16,7 +16,6 @@ class _BaseDependency(StrictModel): name: str manager: Literal["conda", "pip"] = "conda" - optional: bool = False category: str = "main" extras: List[str] = [] diff --git a/conda_lock/pypi_solver.py b/conda_lock/pypi_solver.py index 61aecd70c..65d0e3cfc 100644 --- a/conda_lock/pypi_solver.py +++ b/conda_lock/pypi_solver.py @@ -330,7 +330,7 @@ def solve_pypi( else: planned[pypi_name] = [locked_dep] - lockfile._apply_categories( + lockfile.apply_categories( requested=pip_specs, planned=planned, convert_to_pip_names=True ) diff --git a/conda_lock/src_parser/conda_common.py b/conda_lock/src_parser/conda_common.py index cfab89453..a79293733 100644 --- a/conda_lock/src_parser/conda_common.py +++ b/conda_lock/src_parser/conda_common.py @@ -26,7 +26,6 @@ def conda_spec_to_versioned_dep(spec: str, category: str) -> VersionedDependency name=ms.name, version=ms.get("version", ""), manager="conda", - optional=category != "main", category=category, extras=[], build=ms.get("build"), diff --git a/conda_lock/src_parser/environment_yaml.py b/conda_lock/src_parser/environment_yaml.py index e1e221e72..02821c34f 100644 --- a/conda_lock/src_parser/environment_yaml.py +++ b/conda_lock/src_parser/environment_yaml.py @@ -70,7 +70,6 @@ def _parse_environment_file_for_platform( parse_python_requirement( spec, manager="pip", - optional=category != "main", category=category, normalize_name=False, ) diff --git a/conda_lock/src_parser/pyproject_toml.py b/conda_lock/src_parser/pyproject_toml.py index 745ca569a..9dc81227a 100644 --- a/conda_lock/src_parser/pyproject_toml.py +++ b/conda_lock/src_parser/pyproject_toml.py @@ -155,7 +155,6 @@ def parse_poetry_pyproject_toml( ["tool", "poetry", *section], contents, {} ).items(): category: str = dep_to_extra.get(depname) or default_category - optional: bool = category != "main" manager: Literal["conda", "pip"] = "conda" url = None extras = [] @@ -244,7 +243,6 @@ def parse_poetry_pyproject_toml( url=url, hashes=[hashes], manager=manager, - optional=optional, category=category, extras=extras, ) @@ -255,7 +253,6 @@ def parse_poetry_pyproject_toml( name=name, version=version, manager=manager, - optional=optional, category=category, extras=extras, ) @@ -281,7 +278,6 @@ def specification_with_dependencies( name=depname, version=conda_version, manager="conda", - optional=False, category="main", extras=[], ) @@ -318,7 +314,6 @@ def to_match_spec(conda_dep_name: str, conda_version: Optional[str]) -> str: def parse_python_requirement( requirement: str, manager: Literal["conda", "pip"] = "conda", - optional: bool = False, category: str = "main", normalize_name: bool = True, ) -> Dependency: @@ -345,7 +340,6 @@ def parse_python_requirement( return URLDependency( name=conda_dep_name, manager=manager, - optional=optional, category=category, extras=extras, url=url, @@ -356,7 +350,6 @@ def parse_python_requirement( name=conda_dep_name, version=conda_version or "*", manager=manager, - optional=optional, category=category, extras=extras, ) @@ -387,9 +380,7 @@ def parse_requirements_pyproject_toml( for path, category in sections.items(): for dep in get_in(list(path), contents, []): dependencies.append( - parse_python_requirement( - dep, manager="conda", category=category, optional=category != "main" - ) + parse_python_requirement(dep, manager="conda", category=category) ) return specification_with_dependencies( @@ -420,9 +411,7 @@ def parse_pdm_pyproject_toml( for section, deps in get_in(["tool", "pdm", "dev-dependencies"], contents).items(): dev_reqs.extend( [ - parse_python_requirement( - dep, manager="conda", category="dev", optional=True - ) + parse_python_requirement(dep, manager="conda", category="dev") for dep in deps ] ) diff --git a/tests/test_conda_lock.py b/tests/test_conda_lock.py index 8fbf5a4cd..ba82b43cf 100644 --- a/tests/test_conda_lock.py +++ b/tests/test_conda_lock.py @@ -393,7 +393,6 @@ def test_parse_environment_file_with_pip(pip_environment: Path): VersionedDependency( name="requests-toolbelt", manager="pip", - optional=False, category="main", extras=[], version="=0.9.1", @@ -495,7 +494,6 @@ def test_choose_wheel() -> None: "fastavro": VersionedDependency( name="fastavro", manager="pip", - optional=False, category="main", extras=[], version="1.4.7", @@ -612,7 +610,6 @@ def test_parse_meta_yaml_file(meta_yaml_environment: Path): # Ensure that this platform specific dep is included assert "zlib" in specs assert specs["pytest"].category == "dev" - assert specs["pytest"].optional is True def test_parse_poetry(poetry_pyproject_toml: Path): @@ -628,10 +625,8 @@ def test_parse_poetry(poetry_pyproject_toml: Path): assert specs["sqlite"].version == "<3.34" assert specs["certifi"].version == ">=2019.11.28" assert specs["pytest"].version == ">=5.1.0,<5.2.0" - assert specs["pytest"].optional is True assert specs["pytest"].category == "dev" assert specs["tomlkit"].version == ">=0.7.0,<1.0.0" - assert specs["tomlkit"].optional is True assert specs["tomlkit"].category == "tomlkit" assert res.channels == [Channel.from_string("defaults")] @@ -728,7 +723,6 @@ def test_parse_flit(flit_pyproject_toml: Path): assert specs["sqlite"].version == "<3.34" assert specs["certifi"].version == ">=2019.11.28" assert specs["pytest"].version == ">=5.1.0" - assert specs["pytest"].optional is True assert specs["pytest"].category == "dev" assert specs["toml"].manager == "pip" @@ -752,11 +746,9 @@ def test_parse_pdm(pdm_pyproject_toml: Path): assert specs["certifi"].version == ">=2019.11.28" # PEP 621 optional dependencies (show up in package metadata) assert specs["click"].version == ">=7.0" - assert specs["click"].optional is True assert specs["click"].category == "cli" # PDM dev extras assert specs["pytest"].version == ">=5.1.0" - assert specs["pytest"].optional is True assert specs["pytest"].category == "dev" # Conda channels assert res.channels == [Channel.from_string("defaults")] @@ -1214,7 +1206,6 @@ def test_poetry_version_parsing_constraints( name=package, version=poetry_version_to_conda_version(version) or "", manager="conda", - optional=False, category="main", extras=[], ),