Skip to content

Commit

Permalink
feat: allow self-referencing groups in dev-dependencies (#1890)
Browse files Browse the repository at this point in the history
  • Loading branch information
frostming authored May 6, 2023
1 parent ee1da21 commit 8dcb28f
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 20 deletions.
1 change: 1 addition & 0 deletions news/1890.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow self-referencing groups in dev-dependencies.
43 changes: 23 additions & 20 deletions src/pdm/models/repositories.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,28 @@ def _get_dependencies_from_metadata(self, candidate: Candidate) -> CandidateInfo
summary = prepared.metadata.metadata["Summary"]
return deps, requires_python, summary

def _get_dependency_from_local_package(self, candidate: Candidate) -> CandidateInfo:
"""Adds the local package as a candidate only if the candidate
name is the same as the local package."""
project = self.environment.project
if not project.name or candidate.name != project.name:
raise CandidateInfoNotFound(candidate) from None

reqs = project.pyproject.metadata.get("dependencies", [])
extra_dependencies = project.pyproject.settings.get("dev-dependencies", {})
extra_dependencies.update(project.pyproject.metadata.get("optional-dependencies", {}))
if candidate.req.extras is not None:
reqs = sum(
(extra_dependencies.get(g, []) for g in candidate.req.extras),
[],
)

return (
reqs,
str(self.environment.python_requires),
project.pyproject.metadata.get("description", "UNKNOWN"),
)

def get_hashes(self, candidate: Candidate) -> dict[Link, str] | None:
"""Get hashes of all possible installable candidates
of a given package version.
Expand Down Expand Up @@ -311,6 +333,7 @@ def _get_dependencies_from_json(self, candidate: Candidate) -> CandidateInfo:

def dependency_generators(self) -> Iterable[Callable[[Candidate], CandidateInfo]]:
yield self._get_dependencies_from_cache
yield self._get_dependency_from_local_package
if self.environment.project.config["pypi.json_api"]:
yield self._get_dependencies_from_json
yield self._get_dependencies_from_metadata
Expand Down Expand Up @@ -417,26 +440,6 @@ def _identify_candidate(self, candidate: Candidate) -> tuple:
def _get_dependencies_from_lockfile(self, candidate: Candidate) -> CandidateInfo:
return self.candidate_info[self._identify_candidate(candidate)]

def _get_dependency_from_local_package(self, candidate: Candidate) -> CandidateInfo:
"""Adds the local package as a candidate only if the candidate
name is the same as the local package."""
if candidate.name != self.environment.project.name:
raise CandidateInfoNotFound(candidate) from None

reqs = self.environment.project.pyproject.metadata.get("dependencies", [])
optional_dependencies = self.environment.project.pyproject.metadata.get("optional-dependencies", {})
if candidate.req.extras is not None:
reqs = sum(
(optional_dependencies.get(g, []) for g in candidate.req.extras),
[],
)

return (
reqs,
str(self.environment.python_requires),
self.environment.project.pyproject.metadata.get("description", "UNKNOWN"),
)

def dependency_generators(self) -> Iterable[Callable[[Candidate], CandidateInfo]]:
return (
self._get_dependency_from_local_package,
Expand Down
1 change: 1 addition & 0 deletions src/pdm/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ def _get_dependencies_from_fixture(self, candidate: Candidate) -> tuple[list[str
def dependency_generators(self) -> Iterable[Callable[[Candidate], CandidateInfo]]:
return (
self._get_dependencies_from_cache,
self._get_dependency_from_local_package,
self._get_dependencies_from_fixture,
self._get_dependencies_from_metadata,
)
Expand Down
15 changes: 15 additions & 0 deletions tests/cli/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,18 @@ def test_lock_selected_groups(project, pdm):
assert project.lockfile.groups == ["http"]
assert "requests" in project.locked_repository.all_candidates
assert "pytz" not in project.locked_repository.all_candidates


@pytest.mark.usefixtures("repository")
@pytest.mark.parametrize("to_dev", [False, True])
def test_lock_self_referencing_groups(project, pdm, to_dev):
name = project.name
project.add_dependencies({"requests": parse_requirement("requests")}, to_group="http", dev=to_dev)
project.add_dependencies(
{"pytz": parse_requirement("pytz"), f"{name}[http]": parse_requirement(f"{name}[http]")},
to_group="dev",
dev=True,
)
pdm(["lock", "-G", "dev"], obj=project, strict=True)
assert project.lockfile.groups == ["default", "dev"]
assert "requests" in project.locked_repository.all_candidates

0 comments on commit 8dcb28f

Please sign in to comment.