datastructures.py 3.5 KB

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