You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.2 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. from __future__ import absolute_import, division, unicode_literals
  2. from types import ModuleType
  3. from six import text_type
  4. try:
  5. import xml.etree.cElementTree as default_etree
  6. except ImportError:
  7. import xml.etree.ElementTree as default_etree
  8. __all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair",
  9. "surrogatePairToCodepoint", "moduleFactoryFactory",
  10. "supports_lone_surrogates"]
  11. # Platforms not supporting lone surrogates (\uD800-\uDFFF) should be
  12. # caught by the below test. In general this would be any platform
  13. # using UTF-16 as its encoding of unicode strings, such as
  14. # Jython. This is because UTF-16 itself is based on the use of such
  15. # surrogates, and there is no mechanism to further escape such
  16. # escapes.
  17. try:
  18. _x = eval('"\\uD800"')
  19. if not isinstance(_x, text_type):
  20. # We need this with u"" because of http://bugs.jython.org/issue2039
  21. _x = eval('u"\\uD800"')
  22. assert isinstance(_x, text_type)
  23. except:
  24. supports_lone_surrogates = False
  25. else:
  26. supports_lone_surrogates = True
  27. class MethodDispatcher(dict):
  28. """Dict with 2 special properties:
  29. On initiation, keys that are lists, sets or tuples are converted to
  30. multiple keys so accessing any one of the items in the original
  31. list-like object returns the matching value
  32. md = MethodDispatcher({("foo", "bar"):"baz"})
  33. md["foo"] == "baz"
  34. A default value which can be set through the default attribute.
  35. """
  36. def __init__(self, items=()):
  37. # Using _dictEntries instead of directly assigning to self is about
  38. # twice as fast. Please do careful performance testing before changing
  39. # anything here.
  40. _dictEntries = []
  41. for name, value in items:
  42. if type(name) in (list, tuple, frozenset, set):
  43. for item in name:
  44. _dictEntries.append((item, value))
  45. else:
  46. _dictEntries.append((name, value))
  47. dict.__init__(self, _dictEntries)
  48. self.default = None
  49. def __getitem__(self, key):
  50. return dict.get(self, key, self.default)
  51. # Some utility functions to dal with weirdness around UCS2 vs UCS4
  52. # python builds
  53. def isSurrogatePair(data):
  54. return (len(data) == 2 and
  55. ord(data[0]) >= 0xD800 and ord(data[0]) <= 0xDBFF and
  56. ord(data[1]) >= 0xDC00 and ord(data[1]) <= 0xDFFF)
  57. def surrogatePairToCodepoint(data):
  58. char_val = (0x10000 + (ord(data[0]) - 0xD800) * 0x400 +
  59. (ord(data[1]) - 0xDC00))
  60. return char_val
  61. # Module Factory Factory (no, this isn't Java, I know)
  62. # Here to stop this being duplicated all over the place.
  63. def moduleFactoryFactory(factory):
  64. moduleCache = {}
  65. def moduleFactory(baseModule, *args, **kwargs):
  66. if isinstance(ModuleType.__name__, type("")):
  67. name = "_%s_factory" % baseModule.__name__
  68. else:
  69. name = b"_%s_factory" % baseModule.__name__
  70. if name in moduleCache:
  71. return moduleCache[name]
  72. else:
  73. mod = ModuleType(name)
  74. objs = factory(baseModule, *args, **kwargs)
  75. mod.__dict__.update(objs)
  76. moduleCache[name] = mod
  77. return mod
  78. return moduleFactory