packaging.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. from __future__ import annotations
  2. import functools
  3. import logging
  4. from pip._vendor.packaging import specifiers, version
  5. from pip._vendor.packaging.requirements import Requirement
  6. logger = logging.getLogger(__name__)
  7. @functools.lru_cache(maxsize=32)
  8. def check_requires_python(
  9. requires_python: str | None, version_info: tuple[int, ...]
  10. ) -> bool:
  11. """
  12. Check if the given Python version matches a "Requires-Python" specifier.
  13. :param version_info: A 3-tuple of ints representing a Python
  14. major-minor-micro version to check (e.g. `sys.version_info[:3]`).
  15. :return: `True` if the given Python version satisfies the requirement.
  16. Otherwise, return `False`.
  17. :raises InvalidSpecifier: If `requires_python` has an invalid format.
  18. """
  19. if requires_python is None:
  20. # The package provides no information
  21. return True
  22. requires_python_specifier = specifiers.SpecifierSet(requires_python)
  23. python_version = version.parse(".".join(map(str, version_info)))
  24. return python_version in requires_python_specifier
  25. @functools.lru_cache(maxsize=10000)
  26. def get_requirement(req_string: str) -> Requirement:
  27. """Construct a packaging.Requirement object with caching"""
  28. # Parsing requirement strings is expensive, and is also expected to happen
  29. # with a low diversity of different arguments (at least relative the number
  30. # constructed). This method adds a cache to requirement object creation to
  31. # minimize repeated parsing of the same string to construct equivalent
  32. # Requirement objects.
  33. return Requirement(req_string)