You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

43 line
1.4 KiB

  1. from __future__ import annotations
  2. from collections.abc import Iterable, Iterator
  3. from functools import lru_cache
  4. from typing import TYPE_CHECKING, Callable, TypeVar, Union, overload
  5. import jaraco.text as text
  6. from packaging.requirements import Requirement
  7. if TYPE_CHECKING:
  8. from typing_extensions import TypeAlias
  9. _T = TypeVar("_T")
  10. _StrOrIter: TypeAlias = Union[str, Iterable[str]]
  11. parse_req: Callable[[str], Requirement] = lru_cache()(Requirement)
  12. # Setuptools parses the same requirement many times
  13. # (e.g. first for validation than for normalisation),
  14. # so it might be worth to cache.
  15. def parse_strings(strs: _StrOrIter) -> Iterator[str]:
  16. """
  17. Yield requirement strings for each specification in `strs`.
  18. `strs` must be a string, or a (possibly-nested) iterable thereof.
  19. """
  20. return text.join_continuation(map(text.drop_comment, text.yield_lines(strs)))
  21. # These overloads are only needed because of a mypy false-positive, pyright gets it right
  22. # https://github.com/python/mypy/issues/3737
  23. @overload
  24. def parse(strs: _StrOrIter) -> Iterator[Requirement]: ...
  25. @overload
  26. def parse(strs: _StrOrIter, parser: Callable[[str], _T]) -> Iterator[_T]: ...
  27. def parse(strs: _StrOrIter, parser: Callable[[str], _T] = parse_req) -> Iterator[_T]: # type: ignore[assignment]
  28. """
  29. Replacement for ``pkg_resources.parse_requirements`` that uses ``packaging``.
  30. """
  31. return map(parser, parse_strings(strs))