| import sys | |
| from typing import Any, Dict, Iterable, Iterator, List, Tuple | |
| if sys.version_info >= (3, 11): | |
| import tomllib | |
| else: | |
| from pip._vendor import tomli as tomllib | |
| from pip._vendor.dependency_groups import DependencyGroupResolver | |
| from pip._internal.exceptions import InstallationError | |
| def parse_dependency_groups(groups: List[Tuple[str, str]]) -> List[str]: | |
| """ | |
| Parse dependency groups data as provided via the CLI, in a `[path:]group` syntax. | |
| Raises InstallationErrors if anything goes wrong. | |
| """ | |
| resolvers = _build_resolvers(path for (path, _) in groups) | |
| return list(_resolve_all_groups(resolvers, groups)) | |
| def _resolve_all_groups( | |
| resolvers: Dict[str, DependencyGroupResolver], groups: List[Tuple[str, str]] | |
| ) -> Iterator[str]: | |
| """ | |
| Run all resolution, converting any error from `DependencyGroupResolver` into | |
| an InstallationError. | |
| """ | |
| for path, groupname in groups: | |
| resolver = resolvers[path] | |
| try: | |
| yield from (str(req) for req in resolver.resolve(groupname)) | |
| except (ValueError, TypeError, LookupError) as e: | |
| raise InstallationError( | |
| f"[dependency-groups] resolution failed for '{groupname}' " | |
| f"from '{path}': {e}" | |
| ) from e | |
| def _build_resolvers(paths: Iterable[str]) -> Dict[str, Any]: | |
| resolvers = {} | |
| for path in paths: | |
| if path in resolvers: | |
| continue | |
| pyproject = _load_pyproject(path) | |
| if "dependency-groups" not in pyproject: | |
| raise InstallationError( | |
| f"[dependency-groups] table was missing from '{path}'. " | |
| "Cannot resolve '--group' option." | |
| ) | |
| raw_dependency_groups = pyproject["dependency-groups"] | |
| if not isinstance(raw_dependency_groups, dict): | |
| raise InstallationError( | |
| f"[dependency-groups] table was malformed in {path}. " | |
| "Cannot resolve '--group' option." | |
| ) | |
| resolvers[path] = DependencyGroupResolver(raw_dependency_groups) | |
| return resolvers | |
| def _load_pyproject(path: str) -> Dict[str, Any]: | |
| """ | |
| This helper loads a pyproject.toml as TOML. | |
| It raises an InstallationError if the operation fails. | |
| """ | |
| try: | |
| with open(path, "rb") as fp: | |
| return tomllib.load(fp) | |
| except FileNotFoundError: | |
| raise InstallationError(f"{path} not found. Cannot resolve '--group' option.") | |
| except tomllib.TOMLDecodeError as e: | |
| raise InstallationError(f"Error parsing {path}: {e}") from e | |
| except OSError as e: | |
| raise InstallationError(f"Error reading {path}: {e}") from e | |