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.

332 lines
8.9 KiB

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