collection of python libs developed for testing purposes

bottleneck.py 3.3KB

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