Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow self-referencing groups in dev-dependencies #1890

Merged
merged 2 commits into from
May 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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