add code documentation

This commit is contained in:
S Groesz 2020-10-16 05:13:41 +00:00
parent 535ef1d42b
commit 1eba1c7196
2 changed files with 214 additions and 4 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
__pycache__ __pycache__
*.bak *.bak
*.swp

View File

@ -5,6 +5,14 @@ class Bit:
""" """
def __init__(self, var): def __init__(self, var):
"""
var: Any supported type
Supported types: (bool, int, str, Bit)
bool: True or False
int: 0 = False, anything else = True
str: "0" = False, anything else = True
Bit: Bit = Bit
"""
if not isinstance(var, (bool, int, str, Bit)): if not isinstance(var, (bool, int, str, Bit)):
raise TypeError("Bit must be one of type (int, bool, str)") raise TypeError("Bit must be one of type (int, bool, str)")
if isinstance(var, (int, Bit)): if isinstance(var, (int, Bit)):
@ -20,6 +28,9 @@ class Bit:
self.__bit = var self.__bit = var
def __str__(self): def __str__(self):
"""
Return "0" or "1"
"""
return str(int(self.__bit)) return str(int(self.__bit))
def __int__(self): def __int__(self):
@ -29,9 +40,12 @@ class Bit:
return self.__bit return self.__bit
def __repr__(self): def __repr__(self):
return f'{self.__class__.__name__}({self.__bit!r})' return f'{self.__class__.__name__}({int(self.__bit)})'
def __eq__(self, compare): def __eq__(self, compare):
"""
compare (self) to any supported object
"""
# Massage compare to bool # Massage compare to bool
return bool(self) == bool(Bit(compare)) return bool(self) == bool(Bit(compare))
@ -54,15 +68,21 @@ class Bit:
return self.__bit return self.__bit
def __hash__(self): def __hash__(self):
"""
Not very useful, but provided nonetheless
"""
return hash(self.__bit) return hash(self.__bit)
def toggle(self): def toggle(self):
"""
(self) = Not (Self)
"""
self.__bit = not self.__bit self.__bit = not self.__bit
@property @property
def lie(self): def lie(self):
""" """
Return the opposite of bit, without changing the bit state Return the opposite of bit, without changing the state of (self)
""" """
return not self.__bit return not self.__bit
@ -73,23 +93,43 @@ class Bits:
""" """
def __init__(self, var=0, msb_last=False): def __init__(self, var=0, msb_last=False):
"""
var: any supported variant type that can be interpreted as Bits object
msb_last: True to swap bit order for indexing and slicing. Equivalent
to Bits(Bits(var).stib)
"""
self.__value = 0 self.__value = 0
self.__r_to_l = bool(msb_last) self.__r_to_l = bool(msb_last)
self.__setvalue(var) self.__setvalue(var)
def __bytes__(self): def __bytes__(self):
"""
Get copy(self) as binary object
"""
return bytes([self.__value]) return bytes([self.__value])
def __bool__(self): def __bool__(self):
"""
False if self = Bit(0), otherwise True if self > 0
Use indexing to get value of specific bit, e.g. self[1] will return
Bit(1) if self = "01000000" (left to right)
Use self.stib[1] to get bit 6 in Bit("00000010")
"""
return bool(int(self)) return bool(int(self))
def __int__(self): def __int__(self):
"""
Get integer value of self
"""
return self.__value return self.__value
def __repr__(self): def __repr__(self):
return f'{self.__class__.__name__}({self.__value!r})' return f'{self.__class__.__name__}({self.__value!r})'
def __str__(self): def __str__(self):
"""
Get binary string representation of self
"""
return self.bin() return self.bin()
def __ord__(self): def __ord__(self):
@ -120,9 +160,19 @@ class Bits:
return int(self) >= int(Bits(compare)) return int(self) >= int(Bits(compare))
def __getitem__(self, index): def __getitem__(self, index):
"""
Get Bit at index from self
"""
return self.list()[index] return self.list()[index]
def __setitem__(self, index, value): def __setitem__(self, index, value):
"""
Change value of self by setting or resetting a single Bit
index: The bit to change
value: True or False to set or reset target bit
Index should be an int from 0 to 7
Value is any supported Bit-class compatible object
"""
# we'll take the easy way for now # we'll take the easy way for now
l = self.list() l = self.list()
# str->int->bool->int : accept bool, str, int, return either "0" or "1" # str->int->bool->int : accept bool, str, int, return either "0" or "1"
@ -273,14 +323,33 @@ class Bits:
return self return self
def __ior__(self, other): def __ior__(self, other):
"""
inverse or
"""
self = self | Bits(other) self = self | Bits(other)
return self return self
def __contains__(self, item): def __contains__(self, item):
"""
Return True if binary item is in self
item: The bits to test
Examples:
self = "00110011"
"1" in self -> True
1 in self -> True
"11" in self -> True (equiv to 3 in self, "00000011" in self)
"00010000" in self -> True (equiv to 16 in self)
"00100001" in self -> True (equiv to 33 in self, (32 + 1) in self)
In other words, returns True if bit is set
"""
val = Bits(item) & self val = Bits(item) & self
return val == Bits(item) return val == Bits(item)
def __setvalue(self, var): def __setvalue(self, var):
"""
Internal function to process supported variants (object types) and
set the value of self to int(var)
"""
self.__value = 0 self.__value = 0
if isinstance(var, Bits): if isinstance(var, Bits):
self.__value = int(var) self.__value = int(var)
@ -296,7 +365,19 @@ class Bits:
" value between 0 and 255") " value between 0 and 255")
else: else:
self.__value = 0 self.__value = 0
elif isinstance(var, Bytes):
if int(var) < 256:
self.__value = int(var)
else:
raise ValueError("Bytes object must be < 256")
return list(var)
elif (len(var) > 0) and (len(var) <=8): elif (len(var) > 0) and (len(var) <=8):
# handles: "01010101"
# ["0", "1", "0", "1", "0", "1", "0", "1"]
# [0, 1, 0, 1, 0, 1, 0, 1]
# [False, True, False, True, False, True, False, True]
# Other objects with len 1<>8 that are subscriptable
# and each subscript item can be cast to int
for bit in range(0, len(var)): for bit in range(0, len(var)):
self.__value += (int(bool(int(var[bit]))) * self.__value += (int(bool(int(var[bit]))) *
(2 ** (len(var) - 1 - bit))) (2 ** (len(var) - 1 - bit)))
@ -304,6 +385,11 @@ class Bits:
raise TypeError("Expected object with len <= 8") raise TypeError("Expected object with len <= 8")
def bin(self, pad=True, reverse=False): def bin(self, pad=True, reverse=False):
"""
Return binary string representation of self
pad: True to include leading zeros, False to strip leading zeroes
reverse: True to return binary string representation of self as stiB.
"""
from math import ceil from math import ceil
bitcount = self.__value.bit_length() bitcount = self.__value.bit_length()
ret = "" ret = ""
@ -316,44 +402,79 @@ class Bits:
@property @property
def chr(self): def chr(self):
"""
Return ascii character of int(self)
"""
return chr(self.__value) return chr(self.__value)
@property @property
def int(self): def int(self):
"""
Return int(self)
"""
return int(self) return int(self)
@int.setter @int.setter
def int(self, value): def int(self, value):
"""
Set value of self
value: int(0 - 255)
"""
self.__setvalue(value) self.__setvalue(value)
@property @property
def byte(self): def byte(self):
"""
Return b'(self)'
"""
return bytes(self) return bytes(self)
def reverse(self): def reverse(self):
"""
Set Bits(self) to stiB(self)
"""
self.__setvalue(self.bin()[::-1]) self.__setvalue(self.bin()[::-1])
@property @property
def msb(self): def msb(self):
"""
Return most significant bit
"""
return self.bin()[0] return self.bin()[0]
@property @property
def lsb(self): def lsb(self):
"""
Get least significant bit
"""
return self.bin()[7] return self.bin()[7]
@property @property
def nibble(self): def nibble(self):
"""
list(bit[0:4], bit[4:8])
"""
return [self.bin()[:4], self.bin()[4:]] return [self.bin()[:4], self.bin()[4:]]
@property @property
def rtl(self): def rtl(self):
"""
True if stib, otherwise bits
"""
return self.__r_to_l return self.__r_to_l
@rtl.setter @rtl.setter
def rtl(self, msb_last): def rtl(self, msb_last):
"""
bits|stib
01100011 becomes 11000110
"""
self.__r_to_l = bool(msb_last) self.__r_to_l = bool(msb_last)
def list(self, pad=True, reverse=False): def list(self, pad=True, reverse=False):
"""
Return self as list(of Bit)
"""
ret = [] ret = []
bits = self.bin(pad=pad, reverse=reverse) bits = self.bin(pad=pad, reverse=reverse)
for b in bits: for b in bits:
@ -367,38 +488,65 @@ class Bytes:
""" """
def __init__(self, var=None, byteorder="big"): def __init__(self, var=None, byteorder="big"):
"""
var: a supported variant (object)
byteorder: notimplemented, mostly ignored
"""
self.__raw = bytearray(b'') self.__raw = bytearray(b'')
self.__small = False self.__small = False
self.__iter = None
self.__list_len = None
if byteorder.lower() in ["small", "little"]: if byteorder.lower() in ["small", "little"]:
self.__small = True self.__small = True
if var is not None: if var is not None:
self.__raw = self.__to_bytearray(var) self.__raw = self.__to_bytearray(var)
def __bytes__(self): def __bytes__(self):
"""
Value of self in binary
"""
return bytes(self.__raw) return bytes(self.__raw)
def __int__(self): def __int__(self):
"""
Self, but as an intfant
"""
return self.int() return self.int()
def __repr__(self): def __repr__(self):
"""
Represent self
"""
ret = f'{self.__class__.__module__}.{self.__class__.__name__}' ret = f'{self.__class__.__module__}.{self.__class__.__name__}'
ret += f'({bytes(self)})' ret += f'({bytes(self)})'
return ret return ret
def __index__(self): def __index__(self):
"""
Return int representation of self
"""
return self.int() return self.int()
def __getitem__(self, index): def __getitem__(self, index):
"""
Get single byte from self as Bits object
"""
if not isinstance(index, int): if not isinstance(index, int):
raise TypeError raise TypeError
return Bits(self.__raw[index]) return Bits(self.__raw[index])
def __setitem__(self, index, value): def __setitem__(self, index, value):
"""
Change value of byte in self
"""
if not isinstance(index, int): if not isinstance(index, int):
raise TypeError raise TypeError
self.__raw[index] = int(value) self.__raw[index] = int(value)
def __delitem__(self, index): def __delitem__(self, index):
"""
Delete (remove) byte from self
"""
del self.__raw[index] del self.__raw[index]
def __test_key(self, key): def __test_key(self, key):
@ -409,39 +557,78 @@ class Bytes:
return True return True
def __eq__(self, compare): def __eq__(self, compare):
"""
int(self) == int(compare)
"""
return int(self) == int(compare) return int(self) == int(compare)
def __ne__(self, compare): def __ne__(self, compare):
"""
int(self) != int(compare)
"""
return int(self) != int(compare) return int(self) != int(compare)
def __lt__(self, compare): def __lt__(self, compare):
"""
int(self) < int(compare)
"""
return int(self) < int(compare) return int(self) < int(compare)
def __le__(self, compare): def __le__(self, compare):
"""
int(self) <= int(compare)
"""
return int(self) <= int(compare) return int(self) <= int(compare)
def __gt__(self, compare): def __gt__(self, compare):
"""
int(self) > int(compare)
"""
return int(self) > int(compare) return int(self) > int(compare)
def __ge__(self, compare): def __ge__(self, compare):
"""
int(self) >= int(compare)
"""
return int(self) >= int(compare) return int(self) >= int(compare)
def __hash__(self): def __hash__(self):
"""
NotImplemented
"""
return None return None
def __bool__(self): def __bool__(self):
"""
Return bool(int(self))
"""
return bool(int(self)) return bool(int(self))
def __len__(self): def __len__(self):
"""
Return count of bytes in self
"""
return len(self.__raw) return len(self.__raw)
def __get__(self, instance, owner=None): def __get__(self, instance, owner=None):
"""
get(self)
"""
return self.__raw return self.__raw
def __str__(self): def __str__(self):
"""
Return binary string of self
"""
return self.bin() return self.bin()
def __to_bytearray(self, var): def __to_bytearray(self, var):
"""
Internal function to cast compatible objects to bytearray.
var: Any of (bytearray|int|bytes|str|Bytes|
list(of (bool|int|Bit|Bits|Bytes|bytes)))
returns: Binary representation of var as <bytearray>
"""
retvalue = bytearray(b'') retvalue = bytearray(b'')
byteorder="little" if self.__small else "big" byteorder="little" if self.__small else "big"
if isinstance(var, int): if isinstance(var, int):
@ -458,7 +645,7 @@ class Bytes:
elif isinstance(var, bytearray): elif isinstance(var, bytearray):
retvalue = var retvalue = var
elif isinstance(var, Bytes): elif isinstance(var, Bytes):
retvalue = bytearray(var) retvalue = bytearray(bytes(var))
elif isinstance(var, list): elif isinstance(var, list):
# test first item in list to see if it is Bit # test first item in list to see if it is Bit
if len(var) > 0 and isinstance(var[0], (bool, Bit)): if len(var) > 0 and isinstance(var[0], (bool, Bit)):
@ -498,15 +685,37 @@ class Bytes:
def bytes(self): def bytes(self):
return bytes(self) return bytes(self)
@property
def bits(self):
"""
List of Bit
"""
bitlist = []
for bite in list(self):
bitlist += list(bite)
return bitlist
@property
def stib(self):
"""
Tsil of Bit
"""
return self.bits[::-1]
@property @property
def bytearray(self): def bytearray(self):
"""
Copy of self as bytearray
"""
return bytearray(bytes(self)) return bytearray(bytes(self))
def from_int(self, i, byteorder="big"): def from_int(self, i, byteorder="big"):
signed = False signed = False
# only work with objects that can cast to int
i = int(i)
if i < 0: if i < 0:
signed = True signed = True
length = (len(self.bin(i=i, pad=True)) / 8) length = int((len(self.bin(i=i, pad=True)) / 8))
return i.to_bytes(length=length, return i.to_bytes(length=length,
byteorder=byteorder, byteorder=byteorder,
signed=signed) signed=signed)