Guest User

Untitled

a guest
Jan 20th, 2018
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.04 KB | None | 0 0
  1. import enum
  2.  
  3.  
  4. @enum.unique
  5. class priority(enum.IntEnum):
  6. undef, low, normal, high, airmail = range(-1, 4)
  7.  
  8. def describe(self):
  9. return self.value, self.name
  10.  
  11. @classmethod
  12. def min(cls):
  13. return min(
  14. [e.describe() for e in list(cls)],
  15. key=lambda x: x[0]
  16. )
  17.  
  18. @classmethod
  19. def max(cls):
  20. return max(
  21. [e.describe() for e in list(cls)],
  22. key=lambda x: x[0]
  23. )
  24.  
  25.  
  26. DEFAULT_MAXLENS = {
  27. priority.undef: None,
  28. priority.low: None,
  29. priority.normal: None,
  30. priority.high: 50,
  31. priority.airmail: 10
  32. }
  33.  
  34.  
  35. def get_maxlen(params, key):
  36. return params.get(key, DEFAULT_MAXLENS[key])
  37.  
  38.  
  39. class priority_deque():
  40. """
  41. Base class for priority deque objects.
  42. """
  43.  
  44. @staticmethod
  45. def default_nice_sorter(nices):
  46. return sorted(nices, key=lambda x: x.value, reverse=True)
  47.  
  48. @staticmethod
  49. def random_nice_sorter(nices):
  50. import random
  51. return random.shuffle(nices, len(nices))
  52.  
  53. def __init__(self, *args, **kwargs):
  54. """
  55. params: priority_enum ** (an alternative enum class with the same
  56. member names as the priority class)
  57. retval: a blank priority_deque
  58. raises: AttributeError if priority_enum has an unexpected set
  59. of names
  60. purity: yes
  61.  
  62. Create an empty priority deque.
  63. """
  64. import threading
  65. from collections import deque
  66. self.prty = priority
  67. if "priority_enum" in kwargs:
  68. self.prty = kwargs["priority_enum"]
  69. self._pool = {
  70. self.prty.undef:
  71. deque(maxlen=get_maxlen(kwargs, self.prty.undef)),
  72. self.prty.low:
  73. deque(maxlen=get_maxlen(kwargs, self.prty.low)),
  74. self.prty.normal:
  75. deque(maxlen=get_maxlen(kwargs, self.prty.normal)),
  76. self.prty.high:
  77. deque(maxlen=get_maxlen(kwargs, self.prty.high)),
  78. self.prty.airmail:
  79. deque(maxlen=get_maxlen(kwargs, self.prty.airmail))
  80. }
  81. self.lock = threading.Lock()
  82.  
  83. def push(
  84. self, obj, want_nice=None, force=False,
  85. want_push_func=lambda q, o: q.appendleft(o),
  86. settle_push_func=lambda q, o: q.append(o)
  87. ):
  88. """
  89. params: obj (an object)
  90. want_nice ** (a priority; default: self.prty.normal)
  91. force ** (a bool; default: false)
  92. want_push_func ** (a function q, o -> None;
  93. default: appendleft)
  94. settle_push_func ** (a function q, o -> None;
  95. default: append)
  96. retval: None (a NoneType)
  97. nice (a priority; the priority that obj ended up with)
  98. raises: KeyError if nice is not a key in self.prty (that is, it
  99. is not a key in self._pool)
  100. purity: relative
  101.  
  102. Add a new entry to the pool, with the maximum priority of nice.
  103. The entry may end up with a lower priority because all the other
  104. deques were full.
  105.  
  106. obj can be pushed to the top (right side) of a deque by specifying
  107. push_func like (lambda q, o: q.append(o)).
  108. If the preferred nice value want_nice is full and force=False,
  109. settle_push_func will be used to "settle for" a lower nice
  110. value.
  111. By default, this secondary function pushes to the top of the next
  112. lowest priority.
  113.  
  114. If force=False, this method is not destructive; it will try to
  115. push on a deque in the pool which is not full.
  116. To force pushing an object into a specific priority even if they
  117. are full, set force=True.
  118. """
  119. import time
  120. if want_nice is None:
  121. want_nice = self.prty.normal
  122. if force or self._can_push(want_nice):
  123. time.sleep(0)
  124. with self.lock:
  125. return want_push_func(self._pool[want_nice], obj), want_nice
  126.  
  127. # start from the highest priority and go down
  128. nices = range(want_nice, priority.min()[0])
  129. for nice in nices:
  130. # nice != want_nice
  131. time.sleep(0)
  132. if self._can_push(nice):
  133. with self.lock:
  134. return settle_push_func(self._pool[nice], obj), nice
  135.  
  136. def pop(
  137. self, force_nice=(False, None),
  138. nice_sorter=None, pop_func=lambda q: q.pop()
  139. ):
  140. """
  141. params: force_nice ** (a pair<bool, priority>;
  142. default: (Force, None))
  143. nice_sorter ** (a function n -> s;
  144. default: priority_deque.default_nice_sorter)
  145. pop_func ** (a function q -> o; default: pop)
  146. retval: obj (an object)
  147. nice (a priority; the priority obj had)
  148. raises: KeyError if force_nice isn't long enough
  149. KeyError if force_nice[1] is not a key in self.prty
  150. purity: relative
  151.  
  152. Remove an entry from the pool.
  153. By default, looks for the highest-priority items first.
  154. The priority of the resulting object is returned alongside it.
  155. If no object was found, an object of None and a priority of None
  156. are returned.
  157.  
  158. The deques are sorted by nice_sorter, and the highest-priority non-
  159. empty deque is popped from with pop_func.
  160. To look for lower priorities first, use a function which does not
  161. reverse-sort the priority list.
  162. To use a random priority, use self.random_nice_sorter
  163. To pop from a specific priority, use force_nice=(True, nice).
  164. This will return an object or None (if the priority was empty) and
  165. the provided priority.
  166. """
  167. import time
  168. if nice_sorter is None:
  169. nice_sorter = self.default_nice_sorter
  170. if force_nice[0]:
  171. time.sleep(0)
  172. with self.lock:
  173. return pop_func(self._pool[ force_nice[1] ]), force_nice[1]
  174.  
  175. nices = self._sort_pool(nice_sorter)
  176. for nice in nices:
  177. time.sleep(0)
  178. dq = self._pool[nice]
  179. if len(dq):
  180. with self.lock:
  181. return pop_func(dq), nice
  182. return None, None
  183.  
  184. def peek(
  185. self, force_nice=(False, None),
  186. nice_sorter=None, peek_func=lambda q: q[-1]
  187. ):
  188. """
  189. params: force_nice ** (a pair<bool, priority>;
  190. default: (Force, None))
  191. nice_sorter ** (a function n -> s;
  192. default: priority_deque.default_nice_sorter)
  193. pop_func ** (a function q -> o;
  194. default: lambda q: q[-1])
  195. retval: obj (an object)
  196. nice (a priority; the priority obj has)
  197. raises: KeyError if force_nice isn't long enough
  198. KeyError if force_nice[1] is not a key in self.prty
  199. purity: relative
  200.  
  201. View an entry in the pool.
  202. """
  203. if nice_sorter is None:
  204. nice_sorter = self.default_nice_sorter
  205. if force_nice[0]:
  206. with self.lock:
  207. return peek_func(self._pool[ force_nice[1] ]), force_nice[1]
  208. return self.pop(nice_sorter=nice_sorter, pop_func=peek_func)
  209.  
  210. def clear1(self, nice):
  211. dq = self._pool[nice].copy()
  212. with self.lock:
  213. self._pool[nice].clear()
  214. return dq
  215.  
  216. def clear(self):
  217. pool = self._pool.copy()
  218. for nice in self.prty:
  219. with self.lock:
  220. self._pool[nice].clear()
  221. return pool
  222.  
  223. def _sort_pool(self, nice_sorter=default_nice_sorter):
  224. return nice_sorter( self.prty )
  225.  
  226. def _can_push(self, nice):
  227. if self._pool[nice].maxlen is None:
  228. return True
  229. return len( self._pool[nice] ) < self._pool[nice].maxlen
  230.  
  231. def __repr__(self):
  232. return repr(self._pool)
Add Comment
Please, Sign In to add comment