|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +from typing import TYPE_CHECKING |
| 4 | + |
| 5 | +from packaging.requirements import Requirement |
| 6 | +from packaging.utils import canonicalize_name |
| 7 | +from packaging.version import Version |
| 8 | + |
| 9 | +if TYPE_CHECKING: |
| 10 | + from collections.abc import Iterable |
| 11 | + |
| 12 | + from packaging.specifiers import Specifier |
| 13 | + |
| 14 | +__all__ = ["get_min_requires"] |
| 15 | + |
| 16 | + |
| 17 | +def __dir__() -> list[str]: |
| 18 | + return __all__ |
| 19 | + |
| 20 | + |
| 21 | +def get_min_requires(package: str, reqlist: Iterable[str]) -> Version | None: |
| 22 | + """ |
| 23 | + Read the build requirements from a pyproject.toml file |
| 24 | + and return the minimum version required for the given package. |
| 25 | + Returns None if no minimum version is discovered. |
| 26 | + """ |
| 27 | + |
| 28 | + norm_package = canonicalize_name(package) |
| 29 | + |
| 30 | + requires = [Requirement(req) for req in reqlist] |
| 31 | + |
| 32 | + for req in requires: |
| 33 | + if canonicalize_name(req.name) == norm_package: |
| 34 | + specset = req.specifier |
| 35 | + versions = (min_from_spec(v) for v in specset) |
| 36 | + return min((v for v in versions if v is not None), default=None) |
| 37 | + |
| 38 | + return None |
| 39 | + |
| 40 | + |
| 41 | +def min_from_spec(spec: Specifier) -> Version | None: |
| 42 | + """ |
| 43 | + Return the minimum version from a specifier. |
| 44 | +
|
| 45 | + Returns None if no minimum version is discovered. |
| 46 | + ">" technically doesn't include the minimum, but any |
| 47 | + larger version is acceptable, so it is treated as the |
| 48 | + minimum. |
| 49 | + """ |
| 50 | + |
| 51 | + if spec.operator in {">=", ">", "==", "~="}: |
| 52 | + return Version(spec.version) |
| 53 | + return None |
0 commit comments