_utils.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from __future__ import absolute_import, division, unicode_literals
  2. from types import ModuleType
  3. try:
  4. from collections.abc import Mapping
  5. except ImportError:
  6. from collections import Mapping
  7. from pip._vendor.six import text_type, PY3
  8. if PY3:
  9. import xml.etree.ElementTree as default_etree
  10. else:
  11. try:
  12. import xml.etree.cElementTree as default_etree
  13. except ImportError:
  14. import xml.etree.ElementTree as default_etree
  15. __all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair",
  16. "surrogatePairToCodepoint", "moduleFactoryFactory",
  17. "supports_lone_surrogates"]
  18. # Platforms not supporting lone surrogates (\uD800-\uDFFF) should be
  19. # caught by the below test. In general this would be any platform
  20. # using UTF-16 as its encoding of unicode strings, such as
  21. # Jython. This is because UTF-16 itself is based on the use of such
  22. # surrogates, and there is no mechanism to further escape such
  23. # escapes.
  24. try:
  25. _x = eval('"\\uD800"') # pylint:disable=eval-used
  26. if not isinstance(_x, text_type):
  27. # We need this with u"" because of http://bugs.jython.org/issue2039
  28. _x = eval('u"\\uD800"') # pylint:disable=eval-used
  29. assert isinstance(_x, text_type)
  30. except Exception:
  31. supports_lone_surrogates = False
  32. else:
  33. supports_lone_surrogates = True
  34. class MethodDispatcher(dict):
  35. """Dict with 2 special properties:
  36. On initiation, keys that are lists, sets or tuples are converted to
  37. multiple keys so accessing any one of the items in the original
  38. list-like object returns the matching value
  39. md = MethodDispatcher({("foo", "bar"):"baz"})
  40. md["foo"] == "baz"
  41. A default value which can be set through the default attribute.
  42. """
  43. def __init__(self, items=()):
  44. _dictEntries = []
  45. for name, value in items:
  46. if isinstance(name, (list, tuple, frozenset, set)):
  47. for item in name:
  48. _dictEntries.append((item, value))
  49. else:
  50. _dictEntries.append((name, value))
  51. dict.__init__(self, _dictEntries)
  52. assert len(self) == len(_dictEntries)
  53. self.default = None
  54. def __getitem__(self, key):
  55. return dict.get(self, key, self.default)
  56. def __get__(self, instance, owner=None):
  57. return BoundMethodDispatcher(instance, self)
  58. class BoundMethodDispatcher(Mapping):
  59. """Wraps a MethodDispatcher, binding its return values to `instance`"""
  60. def __init__(self, instance, dispatcher):
  61. self.instance = instance
  62. self.dispatcher = dispatcher
  63. def __getitem__(self, key):
  64. # see https://docs.python.org/3/reference/datamodel.html#object.__get__
  65. # on a function, __get__ is used to bind a function to an instance as a bound method
  66. return self.dispatcher[key].__get__(self.instance)
  67. def get(self, key, default):
  68. if key in self.dispatcher:
  69. return self[key]
  70. else:
  71. return default
  72. def __iter__(self):
  73. return iter(self.dispatcher)
  74. def __len__(self):
  75. return len(self.dispatcher)
  76. def __contains__(self, key):
  77. return key in self.dispatcher
  78. # Some utility functions to deal with weirdness around UCS2 vs UCS4
  79. # python builds
  80. def isSurrogatePair(data):
  81. return (len(data) == 2 and
  82. ord(data[0]) >= 0xD800 and ord(data[0]) <= 0xDBFF and
  83. ord(data[1]) >= 0xDC00 and ord(data[1]) <= 0xDFFF)
  84. def surrogatePairToCodepoint(data):
  85. char_val = (0x10000 + (ord(data[0]) - 0xD800) * 0x400 +
  86. (ord(data[1]) - 0xDC00))
  87. return char_val
  88. # Module Factory Factory (no, this isn't Java, I know)
  89. # Here to stop this being duplicated all over the place.
  90. def moduleFactoryFactory(factory):
  91. moduleCache = {}
  92. def moduleFactory(baseModule, *args, **kwargs):
  93. if isinstance(ModuleType.__name__, type("")):
  94. name = "_%s_factory" % baseModule.__name__
  95. else:
  96. name = b"_%s_factory" % baseModule.__name__
  97. kwargs_tuple = tuple(kwargs.items())
  98. try:
  99. return moduleCache[name][args][kwargs_tuple]
  100. except KeyError:
  101. mod = ModuleType(name)
  102. objs = factory(baseModule, *args, **kwargs)
  103. mod.__dict__.update(objs)
  104. if "name" not in moduleCache:
  105. moduleCache[name] = {}
  106. if "args" not in moduleCache[name]:
  107. moduleCache[name][args] = {}
  108. if "kwargs" not in moduleCache[name][args]:
  109. moduleCache[name][args][kwargs_tuple] = {}
  110. moduleCache[name][args][kwargs_tuple] = mod
  111. return mod
  112. return moduleFactory
  113. def memoize(func):
  114. cache = {}
  115. def wrapped(*args, **kwargs):
  116. key = (tuple(args), tuple(kwargs.items()))
  117. if key not in cache:
  118. cache[key] = func(*args, **kwargs)
  119. return cache[key]
  120. return wrapped