collection of python libs developed for testing purposes

bottleneck.py 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import time
  2. class FrameState:
  3. """Abstraction and tracking of frame state"""
  4. def __init__(self, max_load, size, debug):
  5. self.start = 0
  6. self.pos = 0
  7. self.load = 0
  8. self.allows = None
  9. self.time_ok = None
  10. self.load_ok = None
  11. self.MAX_LOAD = max_load
  12. self.SIZE = size
  13. self.DEBUG_MODE = debug
  14. self.__reset()
  15. def __reset(self):
  16. self.start = time.time()
  17. self.pos = 0
  18. self.load = 0
  19. self.allows = True
  20. def __update(self):
  21. self.pos = time.time() - self.start
  22. self.time_ok = self.pos <= self.SIZE
  23. self.load_ok = self.load <= self.MAX_LOAD - 1
  24. if self.time_ok and self.load_ok:
  25. self.allows = True
  26. elif not self.time_ok:
  27. self.__reset()
  28. elif not self.load_ok:
  29. self.allows = False
  30. def debug(self):
  31. if self.DEBUG_MODE:
  32. msg = ("%4d; %4d; %5s; %0.3f; %0.3f; %5s; %5s"
  33. % (self.load, self.MAX_LOAD, self.load_ok,
  34. self.pos, self.SIZE, self.time_ok,
  35. self.allows))
  36. print(msg)
  37. def is_closed(self):
  38. return not self.is_open()
  39. def is_open(self):
  40. self.__update()
  41. if self.allows:
  42. self.load += 1
  43. return self.allows
  44. class Throttle:
  45. """Throttle to allow only certain amount of iteration per given time.
  46. Usage:
  47. t = bottleneck.Throttle(300)
  48. while True:
  49. call_a_load_sensitive_service()
  50. t.wait() # ensures above loop will not be called more
  51. # than 300 times within 1 minute
  52. t = bottleneck.Throttle(10, 1)
  53. while True:
  54. call_a_load_sensitive_service()
  55. t.wait() # ensures above loop will not be called more
  56. # than 10 times within 1 second
  57. Note that the class will not in any way guarantee any even distribution
  58. of calls in time. If your loop takes 1ms and you throttle to 1000 loops
  59. per 10 minutes, all loops will happen in the first second, and the last
  60. call will block for 599 seconds.
  61. """
  62. def __init__(self, max_load, frame_size=60, debug=False):
  63. """Create new Throttle.
  64. Only required parameter is `max_load`, which is number of times per
  65. frame `Throttle.wait()` returns without blocking. Optionally you can
  66. specify `frame_size` in seconds, which defaults to 60, and debug,
  67. which when true, causes printing of some debugging info.
  68. """
  69. self.max_load = max_load
  70. self.frame_size = frame_size
  71. self.debug = debug
  72. self.waiting = True
  73. self.frame = FrameState(max_load=self.max_load, size=self.frame_size,
  74. debug=self.debug)
  75. def is_closed(self):
  76. """True if throttle is closed."""
  77. return self.frame.is_closed()
  78. def is_open(self):
  79. """True if throttle is open."""
  80. return self.frame.is_open()
  81. def wait(self):
  82. """Return now if throttle is open, otherwise block until it is."""
  83. self.frame.debug()
  84. self.waiting = self.is_closed()
  85. while self.waiting:
  86. self.waiting = self.is_closed()