packaging.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. from __future__ import absolute_import
  2. import logging
  3. import sys
  4. from email.parser import FeedParser # type: ignore
  5. from pip._vendor import pkg_resources
  6. from pip._vendor.packaging import specifiers, version
  7. from pip._internal import exceptions
  8. logger = logging.getLogger(__name__)
  9. def check_requires_python(requires_python):
  10. """
  11. Check if the python version in use match the `requires_python` specifier.
  12. Returns `True` if the version of python in use matches the requirement.
  13. Returns `False` if the version of python in use does not matches the
  14. requirement.
  15. Raises an InvalidSpecifier if `requires_python` have an invalid format.
  16. """
  17. if requires_python is None:
  18. # The package provides no information
  19. return True
  20. requires_python_specifier = specifiers.SpecifierSet(requires_python)
  21. # We only use major.minor.micro
  22. python_version = version.parse('.'.join(map(str, sys.version_info[:3])))
  23. return python_version in requires_python_specifier
  24. def get_metadata(dist):
  25. if (isinstance(dist, pkg_resources.DistInfoDistribution) and
  26. dist.has_metadata('METADATA')):
  27. return dist.get_metadata('METADATA')
  28. elif dist.has_metadata('PKG-INFO'):
  29. return dist.get_metadata('PKG-INFO')
  30. def check_dist_requires_python(dist):
  31. metadata = get_metadata(dist)
  32. feed_parser = FeedParser()
  33. feed_parser.feed(metadata)
  34. pkg_info_dict = feed_parser.close()
  35. requires_python = pkg_info_dict.get('Requires-Python')
  36. try:
  37. if not check_requires_python(requires_python):
  38. raise exceptions.UnsupportedPythonVersion(
  39. "%s requires Python '%s' but the running Python is %s" % (
  40. dist.project_name,
  41. requires_python,
  42. '.'.join(map(str, sys.version_info[:3])),)
  43. )
  44. except specifiers.InvalidSpecifier as e:
  45. logger.warning(
  46. "Package %s has an invalid Requires-Python entry %s - %s",
  47. dist.project_name, requires_python, e,
  48. )
  49. return
  50. def get_installer(dist):
  51. if dist.has_metadata('INSTALLER'):
  52. for line in dist.get_metadata_lines('INSTALLER'):
  53. if line.strip():
  54. return line.strip()
  55. return ''