codekingpro/portable-devtools
115k
1from __future__ import annotations2 3from collections.abc import Iterable, Iterator4from functools import lru_cache5from typing import TYPE_CHECKING, Callable, TypeVar, Union, overload6 7import jaraco.text as text8from packaging.requirements import Requirement9 10if TYPE_CHECKING:11 from typing_extensions import TypeAlias12 13_T = TypeVar("_T")14_StrOrIter: TypeAlias = Union[str, Iterable[str]]15 16 17parse_req: Callable[[str], Requirement] = lru_cache()(Requirement)18# Setuptools parses the same requirement many times19# (e.g. first for validation than for normalisation),20# so it might be worth to cache.21 22 23def parse_strings(strs: _StrOrIter) -> Iterator[str]:24 """25 Yield requirement strings for each specification in `strs`.26 27 `strs` must be a string, or a (possibly-nested) iterable thereof.28 """29 return text.join_continuation(map(text.drop_comment, text.yield_lines(strs)))30 31 32# These overloads are only needed because of a mypy false-positive, pyright gets it right33# https://github.com/python/mypy/issues/373734@overload35def parse(strs: _StrOrIter) -> Iterator[Requirement]: ...36@overload37def parse(strs: _StrOrIter, parser: Callable[[str], _T]) -> Iterator[_T]: ...38def parse(strs: _StrOrIter, parser: Callable[[str], _T] = parse_req) -> Iterator[_T]: # type: ignore[assignment]39 """40 Parse requirements.41 """42 return map(parser, parse_strings(strs))43 