class Bits(int): def __init__(self, byte): self.__setvalue(byte) def __bytes__(self): return bytes([self.__value]) def __int__(self): return self.__value def __repr__(self): ret = f'{self.__class__.__module__}.{self.__class__.__name__}' ret += f'({bytes(self)})' return ret def __str__(self): return self.bin() def __index__(self): return int(self) def __len__(self): return 8 def __getitem__(self, index): return bool(int(self.bin()[index])) #self.bool(key) def __setitem__(self, index, value): # we'll take the easy way for now s = list(self.bin()) # str->int->bool->int : accept bool, str, int, return either "0" or "1" s[index] = str(int(bool(int(value)))) self.__setvalue("".join(s)) def __get__(self, instance, owner): return self.bin() def __setvalue(self, value): self.__value = 0 if isinstance(value, int): if value < 0 or value > 255: raise ValueError("Integer must be between 0 and 255") self.__value = value elif (len(value) > 0) and (len(value) <=8): for bit in range(0, len(value)): self.__value += (int(bool(int(value[bit]))) * (2 ** (len(value) - 1 - bit))) else: raise TypeError("Expected object with len <= 8") def bin(self, pad=True): bitcount = self.__value.bit_length() if pad and ((bitcount % 8) > 0): ret = "0" * (8 - (bitcount % 8)) return ret + bin(self.__value)[2:] @property def chr(self): return chr(self.__value) @property def byte(self): return bytes(self) def reverse(self): self.__setvalue(self.bin()[::-1]) @property def msb(self): return self.bin()[0] @property def lsb(self): return self.bin()[7] @property def nibble(self): return [self.bin()[:4], self.bin()[4:]] class Bytes(bytearray): def __init__(self, b, *args, **kwargs): self.__raw = bytearray(b) def __bytes__(self): return bytes(self.__raw) def __int__(self): return self.int() def __repr__(self): ret = f'{self.__class__.__module__}.{self.__class__.__name__}' ret += f'({bytes(self)})' return ret def __index__(self): return self.int() def __getitem__(self, index): if not isinstance(index, int): raise TypeError return Bits(self.__raw[index]) def __setitem__(self, index, value): if not isinstance(index, int): raise TypeError self.__raw[index] = int(value) def __delitem__(self, index): del self.__raw[index] def __test_key(self, key): if not isinstance(key, int): raise TypeError if key >= len(self.__raw): raise IndexError return True def __eq__(self, compare): return int(self) == int(compare) def __ne__(self, compare): return int(self) != int(compare) def __lt__(self, compare): return int(self) < int(compare) def __le__(self, compare): return int(self) <= int(compare) def __gt__(self, compare): return int(self) > int(compare) def __ge__(self, compare): return int(self) >= int(compare) def __hash__(self): return None def __bool__(self): return bool(int(self)) def __len__(self): return len(self.__raw) def __get__(self, instance, owner=None): return self.__raw def __str__(self): return self.bin() def int(self, _bytes=None, byteorder="big", signed=False): if _bytes is None: _bytes = bytes(self) return int.from_bytes(bytes=_bytes, byteorder=byteorder, signed=signed) def bin(self, i=None, pad=True): if i is None: i = self.int() bitcount = i.bit_length() ret = "" if pad and ((bitcount % 8) > 0): ret = "0" * (8 - (bitcount % 8)) chop = 2 if i < 0: # account for the sign character chop += 1 return ret + bin(i)[chop:] @property def bytes(self): return bytes(self) @property def bytearray(self): return bytearray(bytes(self)) def from_int(self, i, byteorder="big"): signed = False if i < 0: signed = True length = (len(self.bin(i=i, pad=True)) / 8) return i.to_bytes(length=length, byteorder=byteorder, signed=signed)