# See the file "COPYING" for information about the copyright # and warranty status of this software. import sys class Log(object): '''Logging base class''' VERBOSE = True def diagnostic_name(self): return self.__class__.__name__ def log(self, *msgs): if Log.VERBOSE: print('[{}]: '.format(self.diagnostic_name()), *msgs, file=sys.stdout, flush=True) def log_error(self, *msg): print('[{}]: ERROR: {}'.format(self.diagnostic_name()), *msgs, file=sys.stderr, flush=True) # Method decorator. To be used for calculations that will always # deliver the same result. The method cannot take any arguments # and should be accessed as an attribute. class cachedproperty(object): def __init__(self, f): self.f = f def __get__(self, obj, type): if obj is None: return self value = self.f(obj) obj.__dict__[self.f.__name__] = value return value def __set__(self, obj, value): raise AttributeError('cannot set {} on {}' .format(self.f.__name__, obj)) def chunks(items, size): for i in range(0, len(items), size): yield items[i: i + size] def bytes_to_int(be_bytes): '''Interprets a big-endian sequence of bytes as an integer''' assert isinstance(be_bytes, (bytes, bytearray)) value = 0 for byte in be_bytes: value = value * 256 + byte return value def int_to_bytes(value): '''Converts an integer to a big-endian sequence of bytes''' mods = [] while value: value, mod = divmod(value, 256) mods.append(mod) return bytes(reversed(mods))