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.

321 lines
8.2 KiB

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