Some helpers without having a specific module
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

__init__.py 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import logging
  2. import numbers
  3. import os
  4. import time
  5. logger_name = 'HELPERS'
  6. logger = logging.getLogger(logger_name)
  7. class continues_statistic(dict):
  8. KEY_SINGLE_VALUE = '_'
  9. KEY_MEAN_VALUE = 'mean_val'
  10. KEY_MIN_VALUE = 'min_val'
  11. KEY_MAX_VALUE = 'max_val'
  12. KEY_NUM_VALUES = 'num_val'
  13. """
  14. Value can be a single single numeric value: continues_statistic(num) or multivalue statistic: continues_statistic(val_a=continues_statistic(num_a), val_b=continues_statistic(num_b)).
  15. """
  16. def __init__(self, *args, **kwargs):
  17. if len(args) == 1 and isinstance(args[0], numbers.Number):
  18. dict.__init__(self)
  19. self[self.KEY_SINGLE_VALUE] = {
  20. self.KEY_MIN_VALUE: args[0],
  21. self.KEY_MEAN_VALUE: args[0],
  22. self.KEY_MAX_VALUE: args[0],
  23. self.KEY_NUM_VALUES: 1,
  24. }
  25. else:
  26. for key in kwargs:
  27. if isinstance(kwargs[key], numbers.Number):
  28. kwargs[key] = continues_statistic(kwargs[key])
  29. dict.__init__(self, *args, **kwargs)
  30. for key in self:
  31. if type(self[key]) is not continues_statistic:
  32. data = continues_statistic()
  33. if key == self.KEY_SINGLE_VALUE:
  34. data[self.KEY_SINGLE_VALUE] = self[key]
  35. else:
  36. data[self.KEY_SINGLE_VALUE] = self[key][self.KEY_SINGLE_VALUE]
  37. self[key] = data
  38. @property
  39. def __multivalue__(self):
  40. if len(self.keys()) == 0:
  41. raise AttributeError('No data stored in continues statistic')
  42. elif len(self.keys()) == 1:
  43. if list(self.keys())[0] != self.KEY_SINGLE_VALUE:
  44. raise AttributeError("The single value key needs to be %s." % self.KEY_SINGLE_VALUE)
  45. return False
  46. return True
  47. def __add__(self, other):
  48. rv = continues_statistic(self)
  49. if self.__multivalue__:
  50. if self.__multivalue__ != other.__multivalue__ or self.keys() != other.keys():
  51. raise AttributeError("Instances are incompatible")
  52. else:
  53. for key in rv:
  54. rv[key] += other[key]
  55. else:
  56. rv[self.KEY_SINGLE_VALUE][self.KEY_MEAN_VALUE] = (self[self.KEY_SINGLE_VALUE][self.KEY_MEAN_VALUE] * self[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES] + other[self.KEY_SINGLE_VALUE][self.KEY_MEAN_VALUE] * other[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES]) / (self[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES] + other[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES])
  57. rv[self.KEY_SINGLE_VALUE][self.KEY_MIN_VALUE] = min(self[self.KEY_SINGLE_VALUE][self.KEY_MIN_VALUE], other[self.KEY_SINGLE_VALUE][self.KEY_MIN_VALUE])
  58. rv[self.KEY_SINGLE_VALUE][self.KEY_MAX_VALUE] = max(self[self.KEY_SINGLE_VALUE][self.KEY_MAX_VALUE], other[self.KEY_SINGLE_VALUE][self.KEY_MAX_VALUE])
  59. rv[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES] = self[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES]+other[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES]
  60. return rv
  61. def __str__(self):
  62. output_for_value = "mean=%%(%s)s, min=%%(%s)s, max=%%(%s)s, num=%%(%s)s" % (self.KEY_MEAN_VALUE, self.KEY_MIN_VALUE, self.KEY_MAX_VALUE, self.KEY_NUM_VALUES)
  63. if self.__multivalue__:
  64. rv = ""
  65. for key in self:
  66. rv += key + ': ' + str(self[key]) + "\n"
  67. return rv
  68. else:
  69. return output_for_value % self[self.KEY_SINGLE_VALUE]
  70. class ringbuffer(list):
  71. def __init__(self, *args, **kwargs):
  72. self.__max_length__ = kwargs.pop('length')
  73. list.__init__(self, *args, **kwargs)
  74. self.__reduce_list__()
  75. def __reduce_list__(self):
  76. while len(self) > self.__max_length__:
  77. self.pop(0)
  78. def append(self, *args, **kwargs):
  79. rv = list.append(self, *args, **kwargs)
  80. self.__reduce_list__()
  81. return rv
  82. class data_collector(object):
  83. def __init__(self, bufferlength, current_max_age=300.):
  84. self.__current_max_age__ = current_max_age
  85. self.__current_data_rinbuffer__ = ringbuffer(length=3)
  86. #
  87. self.__last_add_data__ = 0
  88. self.__continues_statistic__ = None
  89. self.__yesterdays_statistic__ = None
  90. self.__measurement_day__ = None
  91. #
  92. self.__ringbuffer__ = ringbuffer(length=bufferlength)
  93. def __process_continues_statistic__(self, **kwargs):
  94. # rotate continues_statistic day by day
  95. today = time.strftime('%Y' + os.path.sep + '%m' + os.path.sep + '%d')
  96. if self.__measurement_day__ is None:
  97. self.__measurement_day__ = today
  98. if self.__measurement_day__ != today:
  99. self.__yesterdays_statistic__ = self.__continues_statistic__
  100. self.__continues_statistic__ = None
  101. self.__measurement_day__ = None
  102. # Set or update continues statistic
  103. if self.__continues_statistic__ is None:
  104. self.__continues_statistic__ = continues_statistic(**kwargs)
  105. else:
  106. self.__continues_statistic__ += continues_statistic(**kwargs)
  107. def add_data(self, **kwargs):
  108. logger.debug('Got data %s', repr(kwargs))
  109. self.__last_add_data__ = time.time()
  110. self.__current_data_rinbuffer__.append(kwargs)
  111. self.__process_continues_statistic__(**kwargs)
  112. self.__ringbuffer__.append(kwargs)
  113. @property
  114. def current(self):
  115. if len(self.__current_data_rinbuffer__) == 0:
  116. logger.info('No data available, yet.')
  117. return None
  118. elif time.time() > self.__last_add_data__ + self.__current_max_age__:
  119. logger.info('Data max age reached. No current data available.')
  120. return None
  121. elif len(self.__current_data_rinbuffer__) < 3:
  122. return self.__current_data_rinbuffer__[-1]
  123. else:
  124. rv = {}
  125. for key in self.__current_data_rinbuffer__[0]:
  126. data = []
  127. for entry in self.__current_data_rinbuffer__:
  128. data.append(entry[key])
  129. else:
  130. data.sort()
  131. rv[key] = data[1]
  132. return rv
  133. @property
  134. def todays_statistic(self):
  135. return self.__continues_statistic__
  136. @property
  137. def yesterdays_statistic(self):
  138. return self.__yesterdays_statistic__
  139. @property
  140. def databuffer(self):
  141. return self.__ringbuffer__[:]