|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +import itertools |
3 | 4 | import logging |
4 | 5 | import re |
5 | 6 | from dataclasses import dataclass |
@@ -40,30 +41,52 @@ class PEP621DependencyGetter(DependencyGetter): |
40 | 41 | def get(self) -> DependenciesExtract: |
41 | 42 | dependencies = self._get_dependencies() |
42 | 43 | optional_dependencies = self._get_optional_dependencies() |
| 44 | + dependency_groups_dependencies = self._get_dependency_groups_dependencies() |
43 | 45 |
|
44 | 46 | dev_dependencies_from_optional, remaining_optional_dependencies = ( |
45 | 47 | self._split_development_dependencies_from_optional_dependencies(optional_dependencies) |
46 | 48 | ) |
47 | 49 | return DependenciesExtract( |
48 | 50 | [*dependencies, *remaining_optional_dependencies], |
49 | | - self._get_dev_dependencies(dev_dependencies_from_optional), |
| 51 | + self._get_dev_dependencies(dependency_groups_dependencies, dev_dependencies_from_optional), |
50 | 52 | ) |
51 | 53 |
|
52 | 54 | def _get_dependencies(self) -> list[Dependency]: |
| 55 | + """Extract dependencies from `[project.dependencies]` (https://packaging.python.org/en/latest/specifications/pyproject-toml/#dependencies-optional-dependencies).""" |
53 | 56 | pyproject_data = load_pyproject_toml(self.config) |
54 | 57 | dependency_strings: list[str] = pyproject_data["project"].get("dependencies", []) |
55 | 58 | return self._extract_pep_508_dependencies(dependency_strings) |
56 | 59 |
|
57 | 60 | def _get_optional_dependencies(self) -> dict[str, list[Dependency]]: |
| 61 | + """Extract dependencies from `[project.optional-dependencies]` (https://packaging.python.org/en/latest/specifications/pyproject-toml/#dependencies-optional-dependencies).""" |
58 | 62 | pyproject_data = load_pyproject_toml(self.config) |
59 | 63 |
|
60 | 64 | return { |
61 | 65 | group: self._extract_pep_508_dependencies(dependencies) |
62 | 66 | for group, dependencies in pyproject_data["project"].get("optional-dependencies", {}).items() |
63 | 67 | } |
64 | 68 |
|
65 | | - def _get_dev_dependencies(self, dev_dependencies_from_optional: list[Dependency]) -> list[Dependency]: |
66 | | - return dev_dependencies_from_optional |
| 69 | + def _get_dependency_groups_dependencies(self) -> dict[str, list[Dependency]]: |
| 70 | + """Extract dependencies from `[dependency-groups]` (https://peps.python.org/pep-0735/).""" |
| 71 | + pyproject_data = load_pyproject_toml(self.config) |
| 72 | + |
| 73 | + return { |
| 74 | + # PEP 735 supports maps in dependency groups, to for instance extend existing |
| 75 | + # groups (https://peps.python.org/pep-0735/#dependency-group-include). Since we do not need to treat group |
| 76 | + # extension right now, and there are no other existing key, we want to filter out non-string items. |
| 77 | + group: self._extract_pep_508_dependencies(list(filter(lambda x: isinstance(x, str), dependencies))) |
| 78 | + for group, dependencies in pyproject_data.get("dependency-groups", {}).items() |
| 79 | + } |
| 80 | + |
| 81 | + def _get_dev_dependencies( |
| 82 | + self, |
| 83 | + dependency_groups_dependencies: dict[str, list[Dependency]], |
| 84 | + dev_dependencies_from_optional: list[Dependency], |
| 85 | + ) -> list[Dependency]: |
| 86 | + return [ |
| 87 | + *itertools.chain(*dependency_groups_dependencies.values()), |
| 88 | + *dev_dependencies_from_optional, |
| 89 | + ] |
67 | 90 |
|
68 | 91 | def _check_for_invalid_group_names(self, optional_dependencies: dict[str, list[Dependency]]) -> None: |
69 | 92 | missing_groups = set(self.pep621_dev_dependency_groups) - set(optional_dependencies.keys()) |
|
0 commit comments