__init__.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. """Stuff that differs in different Python versions and platform
  2. distributions."""
  3. from __future__ import absolute_import, division
  4. import os
  5. import sys
  6. from pip._vendor.six import text_type
  7. try:
  8. from logging.config import dictConfig as logging_dictConfig
  9. except ImportError:
  10. from pip.compat.dictconfig import dictConfig as logging_dictConfig
  11. try:
  12. from collections import OrderedDict
  13. except ImportError:
  14. from pip._vendor.ordereddict import OrderedDict
  15. try:
  16. import ipaddress
  17. except ImportError:
  18. try:
  19. from pip._vendor import ipaddress
  20. except ImportError:
  21. import ipaddr as ipaddress
  22. ipaddress.ip_address = ipaddress.IPAddress
  23. ipaddress.ip_network = ipaddress.IPNetwork
  24. try:
  25. import sysconfig
  26. def get_stdlib():
  27. paths = [
  28. sysconfig.get_path("stdlib"),
  29. sysconfig.get_path("platstdlib"),
  30. ]
  31. return set(filter(bool, paths))
  32. except ImportError:
  33. from distutils import sysconfig
  34. def get_stdlib():
  35. paths = [
  36. sysconfig.get_python_lib(standard_lib=True),
  37. sysconfig.get_python_lib(standard_lib=True, plat_specific=True),
  38. ]
  39. return set(filter(bool, paths))
  40. __all__ = [
  41. "logging_dictConfig", "ipaddress", "uses_pycache", "console_to_str",
  42. "native_str", "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile",
  43. "OrderedDict",
  44. ]
  45. if sys.version_info >= (3, 4):
  46. uses_pycache = True
  47. from importlib.util import cache_from_source
  48. else:
  49. import imp
  50. uses_pycache = hasattr(imp, 'cache_from_source')
  51. if uses_pycache:
  52. cache_from_source = imp.cache_from_source
  53. else:
  54. cache_from_source = None
  55. if sys.version_info >= (3,):
  56. def console_to_str(s):
  57. try:
  58. return s.decode(sys.__stdout__.encoding)
  59. except UnicodeDecodeError:
  60. return s.decode('utf_8')
  61. def native_str(s, replace=False):
  62. if isinstance(s, bytes):
  63. return s.decode('utf-8', 'replace' if replace else 'strict')
  64. return s
  65. else:
  66. def console_to_str(s):
  67. return s
  68. def native_str(s, replace=False):
  69. # Replace is ignored -- unicode to UTF-8 can't fail
  70. if isinstance(s, text_type):
  71. return s.encode('utf-8')
  72. return s
  73. def total_seconds(td):
  74. if hasattr(td, "total_seconds"):
  75. return td.total_seconds()
  76. else:
  77. val = td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6
  78. return val / 10 ** 6
  79. def get_path_uid(path):
  80. """
  81. Return path's uid.
  82. Does not follow symlinks:
  83. https://github.com/pypa/pip/pull/935#discussion_r5307003
  84. Placed this function in compat due to differences on AIX and
  85. Jython, that should eventually go away.
  86. :raises OSError: When path is a symlink or can't be read.
  87. """
  88. if hasattr(os, 'O_NOFOLLOW'):
  89. fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
  90. file_uid = os.fstat(fd).st_uid
  91. os.close(fd)
  92. else: # AIX and Jython
  93. # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW
  94. if not os.path.islink(path):
  95. # older versions of Jython don't have `os.fstat`
  96. file_uid = os.stat(path).st_uid
  97. else:
  98. # raise OSError for parity with os.O_NOFOLLOW above
  99. raise OSError(
  100. "%s is a symlink; Will not return uid for symlinks" % path
  101. )
  102. return file_uid
  103. def expanduser(path):
  104. """
  105. Expand ~ and ~user constructions.
  106. Includes a workaround for http://bugs.python.org/issue14768
  107. """
  108. expanded = os.path.expanduser(path)
  109. if path.startswith('~/') and expanded.startswith('//'):
  110. expanded = expanded[1:]
  111. return expanded
  112. # packages in the stdlib that may have installation metadata, but should not be
  113. # considered 'installed'. this theoretically could be determined based on
  114. # dist.location (py27:`sysconfig.get_paths()['stdlib']`,
  115. # py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may
  116. # make this ineffective, so hard-coding
  117. stdlib_pkgs = ('python', 'wsgiref')
  118. if sys.version_info >= (2, 7):
  119. stdlib_pkgs += ('argparse',)
  120. # windows detection, covers cpython and ironpython
  121. WINDOWS = (sys.platform.startswith("win") or
  122. (sys.platform == 'cli' and os.name == 'nt'))
  123. def samefile(file1, file2):
  124. """Provide an alternative for os.path.samefile on Windows/Python2"""
  125. if hasattr(os.path, 'samefile'):
  126. return os.path.samefile(file1, file2)
  127. else:
  128. path1 = os.path.normcase(os.path.abspath(file1))
  129. path2 = os.path.normcase(os.path.abspath(file2))
  130. return path1 == path2