Skip to content

Commit

Permalink
Merge pull request #173 from leroyvn/pdm_support
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusvniekerk authored Mar 15, 2022
2 parents 1d553ea + 48d21ad commit 388db9f
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 11 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,9 @@ Conda lock supports more than just [environment.yml][envyaml] specifications!
Additionally conda-lock supports [meta.yaml][metayaml] (conda-build)
and `pyproject.toml` (
[flit](https://flit.readthedocs.io/en/latest/) and [poetry](https://python-poetry.org)
based). These do come with some gotchas but are generally good enough for the 90% use-case.
[flit](https://flit.readthedocs.io/en/latest/), [pdm](https://pdm.fming.dev) and
[poetry](https://python-poetry.org) based). These do come with some gotchas but
are generally good enough for the 90% use-case.
### meta.yaml
Expand Down
49 changes: 43 additions & 6 deletions conda_lock/src_parser/pyproject_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,18 @@ def parse_pyproject_toml(
contents = toml.load(pyproject_toml)
build_system = get_in(["build-system", "build-backend"], contents)
pep_621_probe = get_in(["project", "dependencies"], contents)
pdm_probe = get_in(["tool", "pdm"], contents)
parse = parse_poetry_pyproject_toml
if pep_621_probe is not None:
parse = partial(
parse_requirements_pyproject_toml,
prefix=("project",),
main_tag="dependencies",
optional_tag="optional-dependencies",
)
if pdm_probe is None:
parse = partial(
parse_requirements_pyproject_toml,
prefix=("project",),
main_tag="dependencies",
optional_tag="optional-dependencies",
)
else:
parse = parse_pdm_pyproject_toml
elif build_system.startswith("poetry"):
parse = parse_poetry_pyproject_toml
elif build_system.startswith("flit"):
Expand Down Expand Up @@ -300,3 +304,36 @@ def parse_requirements_pyproject_toml(
)

return specification_with_dependencies(pyproject_toml_path, contents, dependencies)


def parse_pdm_pyproject_toml(
path: pathlib.Path,
contents: Mapping[str, Any],
) -> LockSpecification:
"""
PDM support. First, a regular PEP621 pass; then, add all dependencies listed
in the 'tool.pdm.dev-dependencies' table with the 'dev' category.
"""
res = parse_requirements_pyproject_toml(
path,
contents,
prefix=("project",),
main_tag="dependencies",
optional_tag="optional-dependencies",
)

dev_reqs = []

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
)
for dep in deps
]
)

res.dependencies.extend(dev_reqs)

return res
13 changes: 10 additions & 3 deletions docs/src_pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ is no lookup for the package it assumes that the PyPI name, and the conda name a
build-backend = "poetry.masonry.api"
```

=== "pep621 (flit)"
=== "pep621 (flit, pdm)"
```{.toml title="pyproject.toml"}
[project]
dependencies = [
Expand All @@ -50,6 +50,13 @@ This will create a conda-lock specification with

pytest >=5.1.0

!!! note ""

PDM also has support for
[development dependencies not listed in distribution metadata](https://pdm.fming.dev/pyproject/tool-pdm/#development-dependencies).
Any dependency found in that section will be added to the `dev` category.
This behavior is experimental and may change in the future.

### pure pip dependencies

If a dependency refers directly to a URL rather than a package name and version,
Expand Down Expand Up @@ -92,7 +99,7 @@ If your pyproject.toml file contains optional dependencies/extras these can be r
pgsql = ["psycopg2"]
```

=== "pep621 (flit)"
=== "pep621 (flit, pdm)"

```{.toml title="pyproject.toml"}
# pyproject.toml
Expand Down Expand Up @@ -164,4 +171,4 @@ sqlite = ">=3.34"
```


[mapping]: https://github.com/regro/cf-graph-countyfair/blob/master/mappings/pypi/grayskull_pypi_mapping.yaml
[mapping]: https://github.com/regro/cf-graph-countyfair/blob/master/mappings/pypi/grayskull_pypi_mapping.yaml
26 changes: 26 additions & 0 deletions tests/test-pdm/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[project]
name = "conda-lock-test-pdm"
authors = ["conda-lock"]
description = ""
requires-python = ">=3.7"
dependencies = [
"requests >=2.13.0",
"toml >=0.10",
]

[project.optional-dependencies]
cli = ["click >=7.0"]

[tool.pdm.dev-dependencies]
test = [
"pytest >=5.1.0",
]

[tool.conda-lock]
channels = [
"defaults",
]

[tool.conda-lock.dependencies]
certifi = ">=2019.11.28"
sqlite = "<3.34"
32 changes: 32 additions & 0 deletions tests/test_conda_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ def flit_pyproject_toml():
return TEST_DIR.joinpath("test-flit").joinpath("pyproject.toml")


@pytest.fixture
def pdm_pyproject_toml():
return TEST_DIR.joinpath("test-pdm").joinpath("pyproject.toml")


@pytest.fixture(
scope="function",
params=[
Expand Down Expand Up @@ -396,6 +401,33 @@ def test_parse_flit(flit_pyproject_toml):
assert res.channels == [Channel.from_string("defaults")]


def test_parse_pdm(pdm_pyproject_toml):
res = parse_pyproject_toml(
pdm_pyproject_toml,
)

specs = {
dep.name: typing.cast(VersionedDependency, dep) for dep in res.dependencies
}

# Base dependencies
assert specs["requests"].version == ">=2.13.0"
assert specs["toml"].version == ">=0.10"
# conda-lock exclusives
assert specs["sqlite"].version == "<3.34"
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")]


def test_run_lock(monkeypatch, zlib_environment, conda_exe):
monkeypatch.chdir(zlib_environment.parent)
if is_micromamba(conda_exe):
Expand Down

0 comments on commit 388db9f

Please sign in to comment.