compat.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. """Stuff that differs in different Python versions and platform
  2. distributions."""
  3. import importlib.resources
  4. import logging
  5. import os
  6. import sys
  7. from typing import IO
  8. __all__ = ["get_path_uid", "stdlib_pkgs", "tomllib", "WINDOWS"]
  9. logger = logging.getLogger(__name__)
  10. def has_tls() -> bool:
  11. try:
  12. import _ssl # noqa: F401 # ignore unused
  13. return True
  14. except ImportError:
  15. pass
  16. from pip._vendor.urllib3.util import IS_PYOPENSSL
  17. return IS_PYOPENSSL
  18. def get_path_uid(path: str) -> int:
  19. """
  20. Return path's uid.
  21. Does not follow symlinks:
  22. https://github.com/pypa/pip/pull/935#discussion_r5307003
  23. Placed this function in compat due to differences on AIX and
  24. Jython, that should eventually go away.
  25. :raises OSError: When path is a symlink or can't be read.
  26. """
  27. if hasattr(os, "O_NOFOLLOW"):
  28. fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
  29. file_uid = os.fstat(fd).st_uid
  30. os.close(fd)
  31. else: # AIX and Jython
  32. # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW
  33. if not os.path.islink(path):
  34. # older versions of Jython don't have `os.fstat`
  35. file_uid = os.stat(path).st_uid
  36. else:
  37. # raise OSError for parity with os.O_NOFOLLOW above
  38. raise OSError(f"{path} is a symlink; Will not return uid for symlinks")
  39. return file_uid
  40. # The importlib.resources.open_text function was deprecated in 3.11 with suggested
  41. # replacement we use below.
  42. if sys.version_info < (3, 11):
  43. open_text_resource = importlib.resources.open_text
  44. else:
  45. def open_text_resource(
  46. package: str, resource: str, encoding: str = "utf-8", errors: str = "strict"
  47. ) -> IO[str]:
  48. return (importlib.resources.files(package) / resource).open(
  49. "r", encoding=encoding, errors=errors
  50. )
  51. if sys.version_info >= (3, 11):
  52. import tomllib
  53. else:
  54. from pip._vendor import tomli as tomllib
  55. # packages in the stdlib that may have installation metadata, but should not be
  56. # considered 'installed'. this theoretically could be determined based on
  57. # dist.location (py27:`sysconfig.get_paths()['stdlib']`,
  58. # py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may
  59. # make this ineffective, so hard-coding
  60. stdlib_pkgs = {"python", "wsgiref", "argparse"}
  61. # windows detection, covers cpython and ironpython
  62. WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt")