This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
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.

307 lines
8.3 KiB

  1. import os
  2. from functools import reduce
  3. from collections import deque
  4. ###{standalone
  5. import sys, re
  6. import logging
  7. logger = logging.getLogger("lark")
  8. logger.addHandler(logging.StreamHandler())
  9. # Set to highest level, since we have some warnings amongst the code
  10. # By default, we should not output any log messages
  11. logger.setLevel(logging.CRITICAL)
  12. Py36 = (sys.version_info[:2] >= (3, 6))
  13. def classify(seq, key=None, value=None):
  14. d = {}
  15. for item in seq:
  16. k = key(item) if (key is not None) else item
  17. v = value(item) if (value is not None) else item
  18. if k in d:
  19. d[k].append(v)
  20. else:
  21. d[k] = [v]
  22. return d
  23. def _deserialize(data, namespace, memo):
  24. if isinstance(data, dict):
  25. if '__type__' in data: # Object
  26. class_ = namespace[data['__type__']]
  27. return class_.deserialize(data, memo)
  28. elif '@' in data:
  29. return memo[data['@']]
  30. return {key:_deserialize(value, namespace, memo) for key, value in data.items()}
  31. elif isinstance(data, list):
  32. return [_deserialize(value, namespace, memo) for value in data]
  33. return data
  34. class Serialize(object):
  35. """Safe-ish serialization interface that doesn't rely on Pickle
  36. Attributes:
  37. __serialize_fields__ (List[str]): Fields (aka attributes) to serialize.
  38. __serialize_namespace__ (list): List of classes that deserialization is allowed to instantiate.
  39. Should include all field types that aren't builtin types.
  40. """
  41. def memo_serialize(self, types_to_memoize):
  42. memo = SerializeMemoizer(types_to_memoize)
  43. return self.serialize(memo), memo.serialize()
  44. def serialize(self, memo=None):
  45. if memo and memo.in_types(self):
  46. return {'@': memo.memoized.get(self)}
  47. fields = getattr(self, '__serialize_fields__')
  48. res = {f: _serialize(getattr(self, f), memo) for f in fields}
  49. res['__type__'] = type(self).__name__
  50. postprocess = getattr(self, '_serialize', None)
  51. if postprocess:
  52. postprocess(res, memo)
  53. return res
  54. @classmethod
  55. def deserialize(cls, data, memo):
  56. namespace = getattr(cls, '__serialize_namespace__', {})
  57. namespace = {c.__name__:c for c in namespace}
  58. fields = getattr(cls, '__serialize_fields__')
  59. if '@' in data:
  60. return memo[data['@']]
  61. inst = cls.__new__(cls)
  62. for f in fields:
  63. try:
  64. setattr(inst, f, _deserialize(data[f], namespace, memo))
  65. except KeyError as e:
  66. raise KeyError("Cannot find key for class", cls, e)
  67. postprocess = getattr(inst, '_deserialize', None)
  68. if postprocess:
  69. postprocess()
  70. return inst
  71. class SerializeMemoizer(Serialize):
  72. "A version of serialize that memoizes objects to reduce space"
  73. __serialize_fields__ = 'memoized',
  74. def __init__(self, types_to_memoize):
  75. self.types_to_memoize = tuple(types_to_memoize)
  76. self.memoized = Enumerator()
  77. def in_types(self, value):
  78. return isinstance(value, self.types_to_memoize)
  79. def serialize(self):
  80. return _serialize(self.memoized.reversed(), None)
  81. @classmethod
  82. def deserialize(cls, data, namespace, memo):
  83. return _deserialize(data, namespace, memo)
  84. try:
  85. STRING_TYPE = basestring
  86. except NameError: # Python 3
  87. STRING_TYPE = str
  88. import types
  89. from functools import wraps, partial
  90. from contextlib import contextmanager
  91. Str = type(u'')
  92. try:
  93. classtype = types.ClassType # Python2
  94. except AttributeError:
  95. classtype = type # Python3
  96. def smart_decorator(f, create_decorator):
  97. if isinstance(f, types.FunctionType):
  98. return wraps(f)(create_decorator(f, True))
  99. elif isinstance(f, (classtype, type, types.BuiltinFunctionType)):
  100. return wraps(f)(create_decorator(f, False))
  101. elif isinstance(f, types.MethodType):
  102. return wraps(f)(create_decorator(f.__func__, True))
  103. elif isinstance(f, partial):
  104. # wraps does not work for partials in 2.7: https://bugs.python.org/issue3445
  105. return wraps(f.func)(create_decorator(lambda *args, **kw: f(*args[1:], **kw), True))
  106. else:
  107. return create_decorator(f.__func__.__call__, True)
  108. try:
  109. import regex
  110. except ImportError:
  111. regex = None
  112. import sre_parse
  113. import sre_constants
  114. categ_pattern = re.compile(r'\\p{[A-Za-z_]+}')
  115. def get_regexp_width(expr):
  116. if regex:
  117. # Since `sre_parse` cannot deal with Unicode categories of the form `\p{Mn}`, we replace these with
  118. # a simple letter, which makes no difference as we are only trying to get the possible lengths of the regex
  119. # match here below.
  120. regexp_final = re.sub(categ_pattern, 'A', expr)
  121. else:
  122. if re.search(categ_pattern, expr):
  123. raise ImportError('`regex` module must be installed in order to use Unicode categories.', expr)
  124. regexp_final = expr
  125. try:
  126. return [int(x) for x in sre_parse.parse(regexp_final).getwidth()]
  127. except sre_constants.error:
  128. raise ValueError(expr)
  129. ###}
  130. def dedup_list(l):
  131. """Given a list (l) will removing duplicates from the list,
  132. preserving the original order of the list. Assumes that
  133. the list entries are hashable."""
  134. dedup = set()
  135. return [x for x in l if not (x in dedup or dedup.add(x))]
  136. try:
  137. from contextlib import suppress # Python 3
  138. except ImportError:
  139. @contextmanager
  140. def suppress(*excs):
  141. '''Catch and dismiss the provided exception
  142. >>> x = 'hello'
  143. >>> with suppress(IndexError):
  144. ... x = x[10]
  145. >>> x
  146. 'hello'
  147. '''
  148. try:
  149. yield
  150. except excs:
  151. pass
  152. try:
  153. compare = cmp
  154. except NameError:
  155. def compare(a, b):
  156. if a == b:
  157. return 0
  158. elif a > b:
  159. return 1
  160. return -1
  161. class Enumerator(Serialize):
  162. def __init__(self):
  163. self.enums = {}
  164. def get(self, item):
  165. if item not in self.enums:
  166. self.enums[item] = len(self.enums)
  167. return self.enums[item]
  168. def __len__(self):
  169. return len(self.enums)
  170. def reversed(self):
  171. r = {v: k for k, v in self.enums.items()}
  172. assert len(r) == len(self.enums)
  173. return r
  174. def combine_alternatives(lists):
  175. """
  176. Accepts a list of alternatives, and enumerates all their possible concatinations.
  177. Examples:
  178. >>> combine_alternatives([range(2), [4,5]])
  179. [[0, 4], [0, 5], [1, 4], [1, 5]]
  180. >>> combine_alternatives(["abc", "xy", '$'])
  181. [['a', 'x', '$'], ['a', 'y', '$'], ['b', 'x', '$'], ['b', 'y', '$'], ['c', 'x', '$'], ['c', 'y', '$']]
  182. >>> combine_alternatives([])
  183. [[]]
  184. """
  185. if not lists:
  186. return [[]]
  187. assert all(l for l in lists), lists
  188. init = [[x] for x in lists[0]]
  189. return reduce(lambda a,b: [i+[j] for i in a for j in b], lists[1:], init)
  190. class FS:
  191. open = open
  192. exists = os.path.exists
  193. def isascii(s):
  194. """ str.isascii only exists in python3.7+ """
  195. try:
  196. return s.isascii()
  197. except AttributeError:
  198. try:
  199. s.encode('ascii')
  200. return True
  201. except (UnicodeDecodeError, UnicodeEncodeError):
  202. return False
  203. class fzset(frozenset):
  204. def __repr__(self):
  205. return '{%s}' % ', '.join(map(repr, self))
  206. def classify_bool(seq, pred):
  207. true_elems = []
  208. false_elems = []
  209. for elem in seq:
  210. if pred(elem):
  211. true_elems.append(elem)
  212. else:
  213. false_elems.append(elem)
  214. return true_elems, false_elems
  215. def bfs(initial, expand):
  216. open_q = deque(list(initial))
  217. visited = set(open_q)
  218. while open_q:
  219. node = open_q.popleft()
  220. yield node
  221. for next_node in expand(node):
  222. if next_node not in visited:
  223. visited.add(next_node)
  224. open_q.append(next_node)
  225. def _serialize(value, memo):
  226. if isinstance(value, Serialize):
  227. return value.serialize(memo)
  228. elif isinstance(value, list):
  229. return [_serialize(elem, memo) for elem in value]
  230. elif isinstance(value, frozenset):
  231. return list(value) # TODO reversible?
  232. elif isinstance(value, dict):
  233. return {key:_serialize(elem, memo) for key, elem in value.items()}
  234. # assert value is None or isinstance(value, (int, float, str, tuple)), value
  235. return value