datastructures.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. """
  2. Custom Datastructures
  3. """
  4. from UserList import UserList
  5. from Queue import Queue
  6. from Queue import Empty as QueueEmpty
  7. import traceback
  8. class PositionQueue(UserList):
  9. """A positional queue of a specific length, with slots that are either
  10. filled or unfilled. When all of the positions are filled, the queue
  11. is considered :meth:`full`.
  12. :param length: see :attr:`length`.
  13. .. attribute:: length
  14. The number of items required for the queue to be considered full.
  15. """
  16. class UnfilledPosition(object):
  17. """Describes an unfilled slot."""
  18. def __init__(self, position):
  19. self.position = position
  20. def __init__(self, length):
  21. self.length = length
  22. self.data = map(self.UnfilledPosition, xrange(length))
  23. def full(self):
  24. """Returns ``True`` if all of the slots has been filled."""
  25. return len(self) >= self.length
  26. def __len__(self):
  27. """``len(self)`` -> number of slots filled with real values."""
  28. return len(self.filled)
  29. @property
  30. def filled(self):
  31. """Returns the filled slots as a list."""
  32. return filter(lambda v: not isinstance(v, self.UnfilledPosition),
  33. self.data)
  34. class ExceptionInfo(object):
  35. """Exception wrapping an exception and its traceback.
  36. :param exc_info: The exception tuple info as returned by
  37. :func:`traceback.format_exception`.
  38. .. attribute:: exception
  39. The original exception.
  40. .. attribute:: traceback
  41. A traceback from the point when :attr:`exception` was raised.
  42. """
  43. def __init__(self, exc_info):
  44. type_, exception, tb = exc_info
  45. self.exception = exception
  46. self.traceback = '\n'.join(traceback.format_exception(*exc_info))
  47. def __str__(self):
  48. return str(self.exception)
  49. def __repr__(self):
  50. return "<%s.%s: %s" % (
  51. self.__class__.__module__,
  52. self.__class__.__name__,
  53. str(self.exception))
  54. def consume_queue(queue):
  55. while True:
  56. try:
  57. yield queue.get_nowait()
  58. except QueueEmpty:
  59. break
  60. class SharedCounter(object):
  61. """An integer that can be updated by several threads at once.
  62. Please note that the final value is not synchronized, this means
  63. that you should not update the value by using a previous value, the only
  64. reliable operations are increment and decrement.
  65. Example
  66. >>> max_clients = SharedCounter(initial_value=10)
  67. # Thread one
  68. >>> max_clients += 1 # OK (safe)
  69. # Thread two
  70. >>> max_clients -= 3 # OK (safe)
  71. # Main thread
  72. >>> if client >= int(max_clients): # Max clients now at 8
  73. ... wait()
  74. >>> max_client = max_clients + 10 # NOT OK (unsafe)
  75. """
  76. def __init__(self, initial_value):
  77. self._value = initial_value
  78. self._modify_queue = Queue()
  79. def increment(self, n=1):
  80. """Increment value."""
  81. self += n
  82. def decrement(self, n=1):
  83. """Decrement value."""
  84. self -= n
  85. def _update_value(self):
  86. self._value += sum(consume_queue(self._modify_queue))
  87. return self._value
  88. def __iadd__(self, y):
  89. """``self += y``"""
  90. self._modify_queue.put(y * +1)
  91. return self
  92. def __isub__(self, y):
  93. """``self -= y``"""
  94. self._modify_queue.put(y * -1)
  95. return self
  96. def __int__(self):
  97. """``int(self) -> int``"""
  98. return self._update_value()
  99. def __repr__(self):
  100. return "<SharedCounter: int(%s)>" % str(int(self))