Compare commits
No commits in common. "master" and "1.0.1" have entirely different histories.
|
@ -1,7 +1,3 @@
|
||||||
__pycache__
|
__pycache__
|
||||||
*.bak
|
*.bak
|
||||||
*.swp
|
*.swp
|
||||||
build/
|
|
||||||
dist/
|
|
||||||
*.egg-info
|
|
||||||
*.token
|
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -1,10 +1,10 @@
|
||||||
init:
|
init:
|
||||||
pip3 install --user -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
test:
|
test:
|
||||||
python3 -m unittest -v tests/test_bit.py
|
python -m unittest -v tests/test_bit.py
|
||||||
python3 -m unittest -v tests/test_bits.py
|
python -m unittest -v tests/test_bits.py
|
||||||
python3 -m unittest -v tests/test_bytes.py
|
python -m unittest -v tests/test_bytes.py
|
||||||
|
|
||||||
.PHONY: init test
|
.PHONY: init test
|
||||||
|
|
||||||
|
|
24
README.md
24
README.md
|
@ -1,27 +1,3 @@
|
||||||
# Bits
|
# Bits
|
||||||
|
|
||||||
Helps manage your bits!
|
Helps manage your bits!
|
||||||
|
|
||||||
Intended to be compatible with Python 3.6+. Written and tested against Python
|
|
||||||
3.8.5 Ubuntu 20.04.1 LTS.
|
|
||||||
|
|
||||||
If something doesn't work in Python 3.6, it's a bug. Please report any such
|
|
||||||
bugs if they are encountered.
|
|
||||||
|
|
||||||
# PyPI
|
|
||||||
|
|
||||||
View on PyPI at [https://pypi.org/project/binary-bits/](https://pypi.org/project/binary-bits/)
|
|
||||||
|
|
||||||
Install from PyPI:
|
|
||||||
python3 -m pip install binary-bits --upgrade
|
|
||||||
|
|
||||||
Use in your project:
|
|
||||||
```python
|
|
||||||
import bits
|
|
||||||
|
|
||||||
my_bytes = bits.Bytes(bytes.fromhex('deadbeef'))
|
|
||||||
```
|
|
||||||
|
|
||||||
# Similar projects
|
|
||||||
## [py-flags](https://pypi.org/project/py-flags/)
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from .main import Bit, Bits, Bytes
|
|
@ -1,218 +1,16 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
============================
|
|
||||||
Binary manipulation classes
|
|
||||||
============================
|
|
||||||
|
|
||||||
Provides classes that assist in managing, comparing, transforming and working
|
|
||||||
with binary data in general.
|
|
||||||
|
|
||||||
-----------------
|
|
||||||
Provided Classes
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Bit
|
|
||||||
===
|
|
||||||
The Bit is the smallest representation of binary data and represents True or
|
|
||||||
False. This class provides methods to perform binary comparisons and
|
|
||||||
conversions between different types that can be used to represent a single
|
|
||||||
binary value.
|
|
||||||
|
|
||||||
Bits
|
|
||||||
====
|
|
||||||
A Byte is the representation of 8 Bits. The Byte class provides methods to
|
|
||||||
compare a single binary Byte to other data types. The Class also provides
|
|
||||||
binary math functions and allows getting and setting the state of individual
|
|
||||||
Bits.
|
|
||||||
|
|
||||||
Bytes
|
|
||||||
=====
|
|
||||||
The Bytes class allows an arbitrary amount of binary data to be represented.
|
|
||||||
The Bytes class provides access to each byte using the Byte class, which
|
|
||||||
further allows all the methods to be used on the binary data provided by the
|
|
||||||
Byte and Bit classes. Bytes can be compared and converted between several
|
|
||||||
different data types.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Bit:
|
class Bit:
|
||||||
"""
|
"""
|
||||||
====
|
Provide a flexible bit representation
|
||||||
Bit
|
|
||||||
====
|
|
||||||
|
|
||||||
A single binary bit representation of True or False
|
|
||||||
|
|
||||||
A Bit object can be compared and converted to int, str, bool and other Bit
|
|
||||||
objects. The Bit class is backed by a single bool variable. This backing
|
|
||||||
bool object is converted as necessary to provide conversions and
|
|
||||||
comparisons with other data types. Keep this in mind as converting an
|
|
||||||
object to Bit and then attempting to convert back to the original object
|
|
||||||
may not yield the exact same value.
|
|
||||||
|
|
||||||
In the case of comparisons, the object being compared is cast as a Bit
|
|
||||||
object, and the two Bit objects are then compared with each other and the
|
|
||||||
result of the comparison is returned.
|
|
||||||
|
|
||||||
----------------
|
|
||||||
Type Conversion
|
|
||||||
----------------
|
|
||||||
The objects that can be converted to and from a Bit include *bool*, *int*,
|
|
||||||
*str* and other *Bit* objects.
|
|
||||||
|
|
||||||
Convert *bool* to *Bit*:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
/>/>/> a_bit = Bit(True)
|
|
||||||
/>/>/> a_bit
|
|
||||||
Bit(1)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *Bit* to *bool*:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
/>/>/> a_bool = bool(Bit(True))
|
|
||||||
/>/>/> a_bool
|
|
||||||
True
|
|
||||||
/>/>/> type(a_bool)
|
|
||||||
<class 'bool'>
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *int* to *Bit*:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
/>/>/> unset_bit = Bit(0)
|
|
||||||
/>/>/> unset_bit
|
|
||||||
Bit(0)
|
|
||||||
/>/>/> set_bit = Bit(1)
|
|
||||||
/>/>/> set_bit
|
|
||||||
Bit(1)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *Bit* to *int*:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
/>/>/> my_int = int(Bit(1))
|
|
||||||
/>/>/> my_int
|
|
||||||
1
|
|
||||||
/>/>/> type(my_int)
|
|
||||||
<class 'int'>
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
.. note:: The only values allowed for *int* are **0** and **1**
|
|
||||||
|
|
||||||
Convert *str* to *Bit*:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
/>/>/> unset_bit = Bit("0")
|
|
||||||
/>/>/> unset_bit
|
|
||||||
Bit(0)
|
|
||||||
/>/>/> set_bit = Bit("1")
|
|
||||||
/>/>/> set_bit
|
|
||||||
Bit(1)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *Bit* to *str*:
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_str = str(Bit(False))
|
|
||||||
/>/>/> my_str
|
|
||||||
'0'
|
|
||||||
/>/>/> type(my_str)
|
|
||||||
<class 'str'>
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
.. note:: The only *str* characters allowed are a single **0** or **1**
|
|
||||||
|
|
||||||
|
|
||||||
------------
|
|
||||||
Comparisons
|
|
||||||
------------
|
|
||||||
A Bit object can be compared to any object which can be cast to a Bit
|
|
||||||
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> 0 == Bit(False) == Bit("0") == Bit(0) == False
|
|
||||||
True
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
.. note:: Comparing an object with a value that cannot be cast to Bit will
|
|
||||||
return a ValueError.
|
|
||||||
|
|
||||||
-----------------
|
|
||||||
Rich Comparisons
|
|
||||||
-----------------
|
|
||||||
Bit objects also support "rich comparisons". For example:
|
|
||||||
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> Bit(False) < 1
|
|
||||||
True
|
|
||||||
/>/>/> Bit(True) <= 1
|
|
||||||
True
|
|
||||||
/>/>/> Bit(False) <= "1"
|
|
||||||
True
|
|
||||||
/>/>/> Bit(False) != True
|
|
||||||
True
|
|
||||||
/>/>/> Bit(True) >= False
|
|
||||||
False
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
|
|
||||||
--------
|
|
||||||
Methods
|
|
||||||
--------
|
|
||||||
The action method `toggle` is provided for convenience.
|
|
||||||
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> Bit(False).toggle()
|
|
||||||
Bit(1)
|
|
||||||
/>/>/> Bit(True).toggle() == False
|
|
||||||
True
|
|
||||||
/>/>/> int(Bit(False).toggle())
|
|
||||||
1
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
The `set` and `unset` methods are also provided to explicitely set the
|
|
||||||
value of Bit.
|
|
||||||
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> a_bit = Bit(0)
|
|
||||||
/>/>/> a_bit
|
|
||||||
Bit(0)
|
|
||||||
/>/>/> a_bit.set()
|
|
||||||
/>/>/> a_bit
|
|
||||||
Bit(1)
|
|
||||||
/>/>/> a_bit.unset()
|
|
||||||
/>/>/> a_bit
|
|
||||||
Bit(0)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
|
|
||||||
-----------
|
|
||||||
Properties
|
|
||||||
-----------
|
|
||||||
The `lie` property returns the opposite value of Bit as a *bool*. Unlike
|
|
||||||
the `toggle` method, `lie` does not change the value of the Bit.
|
|
||||||
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> Bit(1).lie
|
|
||||||
False
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, var):
|
def __init__(self, var):
|
||||||
"""
|
"""
|
||||||
var: Any supported type
|
var: Any supported type
|
||||||
Supported types: (bool, int, str, Bit)
|
Supported types: (bool, int, str, Bit)
|
||||||
bool: True or False
|
bool: True or False
|
||||||
int: 0 = False, 1 = True
|
int: 0 = False, anything else = True
|
||||||
str: "0" = False, "1" = True
|
str: "0" = False, anything else = True
|
||||||
Bit: Bit = Bit
|
Bit: Bit = Bit
|
||||||
"""
|
"""
|
||||||
if not isinstance(var, (bool, int, str, Bit)):
|
if not isinstance(var, (bool, int, str, Bit)):
|
||||||
|
@ -230,22 +28,25 @@ class Bit:
|
||||||
self.__bit = var
|
self.__bit = var
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return '0' or '1'"""
|
"""
|
||||||
|
Return "0" or "1"
|
||||||
|
"""
|
||||||
return str(int(self.__bit))
|
return str(int(self.__bit))
|
||||||
|
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
"""Return 0 or 1"""
|
|
||||||
return int(self.__bit)
|
return int(self.__bit)
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
"""Returns True or False"""
|
|
||||||
return self.__bit
|
return self.__bit
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'{self.__class__.__name__}({int(self.__bit)})'
|
return f'{self.__class__.__name__}({int(self.__bit)})'
|
||||||
|
|
||||||
def __eq__(self, compare):
|
def __eq__(self, compare):
|
||||||
"""compare (self) to any supported object"""
|
"""
|
||||||
|
compare (self) to any supported object
|
||||||
|
"""
|
||||||
|
# Massage compare to bool
|
||||||
return bool(self) == bool(Bit(compare))
|
return bool(self) == bool(Bit(compare))
|
||||||
|
|
||||||
def __ne__(self, compare):
|
def __ne__(self, compare):
|
||||||
|
@ -267,257 +68,28 @@ class Bit:
|
||||||
return self.__bit
|
return self.__bit
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
"""Not very useful, but provided nonetheless"""
|
"""
|
||||||
|
Not very useful, but provided nonetheless
|
||||||
|
"""
|
||||||
return hash(self.__bit)
|
return hash(self.__bit)
|
||||||
|
|
||||||
def toggle(self):
|
def toggle(self):
|
||||||
"""Change the state of (self) to Not (self)"""
|
"""
|
||||||
|
(self) = Not (Self)
|
||||||
|
"""
|
||||||
self.__bit = not self.__bit
|
self.__bit = not self.__bit
|
||||||
|
|
||||||
def set(self):
|
|
||||||
"""Set Bit to True"""
|
|
||||||
self.__bit = True
|
|
||||||
|
|
||||||
def unset(self):
|
|
||||||
"""Set Bit to False"""
|
|
||||||
self.__bit = False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lie(self):
|
def lie(self):
|
||||||
"""Return the opposite of bit, without changing the state of (self)"""
|
"""
|
||||||
|
Return the opposite of bit, without changing the state of (self)
|
||||||
|
"""
|
||||||
return not self.__bit
|
return not self.__bit
|
||||||
|
|
||||||
|
|
||||||
class Bits:
|
class Bits:
|
||||||
"""
|
"""
|
||||||
=====
|
Provide bit operation helpers.
|
||||||
Bits
|
|
||||||
=====
|
|
||||||
|
|
||||||
A single byte of data with helper methods and properties.
|
|
||||||
|
|
||||||
A Bits object provides many helpful methods for working with a byte of
|
|
||||||
information. The backing object is a single int, from which all operations
|
|
||||||
and conversions are performed. A Bits object can be converted and compared
|
|
||||||
to *bytes*, *int*, *str*, *list(of Bit)*, *bool* and other *Bits* objects.
|
|
||||||
The custom object *Bytes* can also be cast to a Bits object, as long as the
|
|
||||||
*Bytes* object has an *int* value >= **0** and <= **255**.
|
|
||||||
|
|
||||||
When comparing or operating on *Bits* objects with objects of a different
|
|
||||||
type, the *operand* object will first be cast to a Bits object. In this
|
|
||||||
way, any object which can be used to create a *Bits* object can also be
|
|
||||||
used to perform operations with *Bits*.
|
|
||||||
|
|
||||||
----------------
|
|
||||||
Type Conversion
|
|
||||||
----------------
|
|
||||||
The objects that can be converted to and from *Bits* include *bytes*,
|
|
||||||
*int*, *str*, *list*, *bool* and other *Bits* objects. When using a list,
|
|
||||||
the length of the list must be 8 or less, each list item must be castable
|
|
||||||
to *int*, and each item will be evaluated as either *True* or *False*.
|
|
||||||
|
|
||||||
Convert *bool* to *Bits*:
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits(True)
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(1)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *bytes* to *Bits*:
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits(b'\\xab')
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(171)
|
|
||||||
/>/>/> my_bits = Bits(bytes([210]))
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(210)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *int* to *Bits*:
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits(234)
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(234)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *str* to *Bits*:
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits("01010101")
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(85)
|
|
||||||
/>/>/> my_bits = Bits("11")
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(3)
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
Convert *list* to *Bits*:
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits(["0", "1", "0", "1", "0", "1", "0", "1"])
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(85)
|
|
||||||
/>/>/> my_bits = Bits([0, 1, 0, 1, 0, 1, 0, 1])
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(85)
|
|
||||||
/>/>/> my_bits = Bits([False, True, False, True, False, True])
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(21)
|
|
||||||
/>/>/> my_bits = Bits([True, True])
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(3)
|
|
||||||
/>/>/> my_bits = Bits([0, "1", False, True, "0", Bit(1), Bit(0), 127])
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(85)
|
|
||||||
|
|
||||||
.. note:: Each item in a list will be evaluated to either True or False.
|
|
||||||
|
|
||||||
|
|
||||||
-------------
|
|
||||||
Type Casting
|
|
||||||
-------------
|
|
||||||
Bits objects support casting to multiple different types.
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits(16)
|
|
||||||
/>/>/> str(my_bits)
|
|
||||||
'00010000'
|
|
||||||
/>/>/> int(my_bits)
|
|
||||||
16
|
|
||||||
/>/>/> bin(my_bits)
|
|
||||||
'0b10000'
|
|
||||||
/>/>/> bool(my_bits)
|
|
||||||
True
|
|
||||||
/>/>/> list(my_bits)
|
|
||||||
[Bit(0), Bit(0), Bit(0), Bit(1), Bit(0), Bit(0), Bit(0), Bit(0)]
|
|
||||||
/>/>/> bytes(my_bits)
|
|
||||||
b'\x10'
|
|
||||||
/>/>/> bytearray([my_bits])
|
|
||||||
bytearray(b'\x10')
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
|
|
||||||
-------------
|
|
||||||
Subscripting
|
|
||||||
-------------
|
|
||||||
Subscripting can be used to query or modify each Bit.
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits('01101110')
|
|
||||||
/>/>/> my_bits[3]
|
|
||||||
Bit(0)
|
|
||||||
/>/>/> my_bits[3] = True
|
|
||||||
/>/>/> my_bits[3]
|
|
||||||
Bit(1)
|
|
||||||
/>/>/> str(my_bits)
|
|
||||||
'01111110')
|
|
||||||
/>/>/> list(my_bits)
|
|
||||||
[Bit(0), Bit(1), Bit(1), Bit(1), Bit(1), Bit(1), Bit(1), Bit(0)]
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
|
|
||||||
------------
|
|
||||||
Comparisons
|
|
||||||
------------
|
|
||||||
Bits objects can be compared to any object which can be cast to a Bits
|
|
||||||
object. This goes both ways.
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits('01101110')
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(110)
|
|
||||||
/>/>/> 110 == my_bits
|
|
||||||
True
|
|
||||||
/>/>/> 111 == my_bits
|
|
||||||
False
|
|
||||||
/>/>/> 111 > my_bits
|
|
||||||
True
|
|
||||||
/>/>/> my_bits > 112
|
|
||||||
False
|
|
||||||
/>/>/> b'n' == my_bits
|
|
||||||
True
|
|
||||||
/>/>/> my_bits >= b'#'
|
|
||||||
True
|
|
||||||
/>/>/> my_bits >= '10000000'
|
|
||||||
False
|
|
||||||
/>/>/> '10000000' >= my_bits
|
|
||||||
True
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
|
||||||
Bit-Masks and Flags
|
|
||||||
--------------------
|
|
||||||
Bits objects support bitmask and flag operations.
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits('01101110')
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(110)
|
|
||||||
/>/>/> 110 in my_bits
|
|
||||||
True
|
|
||||||
/>/>/> Bits('00000010') in my_bits
|
|
||||||
True
|
|
||||||
/>/>/> pow_2 = [0, 1, 2, 4, 8, 16, 32, 64, 128]
|
|
||||||
/>/>/> for p2 in pow_2:
|
|
||||||
... print(str(Bits(p2)))
|
|
||||||
...
|
|
||||||
00000000
|
|
||||||
00000001
|
|
||||||
00000010
|
|
||||||
00000100
|
|
||||||
00001000
|
|
||||||
00010000
|
|
||||||
00100000
|
|
||||||
01000000
|
|
||||||
10000000
|
|
||||||
/>/>/> for p2 in pow_2:
|
|
||||||
... print(str(p2) + ' in Bits(110): ' + p2 in my_bits)
|
|
||||||
...
|
|
||||||
0 in Bits(110): True
|
|
||||||
1 in Bits(110): False
|
|
||||||
2 in Bits(110): True
|
|
||||||
4 in Bits(110): True
|
|
||||||
8 in Bits(110): True
|
|
||||||
16 in Bits(110): False
|
|
||||||
32 in Bits(110): True
|
|
||||||
64 in Bits(110): True
|
|
||||||
128 in Bits(110): False
|
|
||||||
/>/>/> str(Bits(14))
|
|
||||||
'00001110'
|
|
||||||
/>/>/> 14 in my_bits
|
|
||||||
True
|
|
||||||
/>/>/> (0 + 2 + 4 + 8) in my_bits
|
|
||||||
True
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
|
|
||||||
-------------------
|
|
||||||
Bitwise operations
|
|
||||||
-------------------
|
|
||||||
Binary bitwise operations are supported.
|
|
||||||
.. code-block: python
|
|
||||||
|
|
||||||
/>/>/> my_bits = Bits('01101110')
|
|
||||||
/>/>/> my_bits
|
|
||||||
Bits(110)
|
|
||||||
/>/>/> str(my_bits & '0011')
|
|
||||||
'00000010'
|
|
||||||
/>/>/> str(my_bits >> 3)
|
|
||||||
'00001101'
|
|
||||||
/>/>/> str(my_bits << 1)
|
|
||||||
'11011100'
|
|
||||||
/>/>/> str(my_bits|'10111110')
|
|
||||||
'11111110'
|
|
||||||
/>/>/> str(my_bits^'10101010')
|
|
||||||
'11000100'
|
|
||||||
/>/>/> str(~my_bits)
|
|
||||||
'10010001'
|
|
||||||
/>/>/>
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, var=0, msb_last=False):
|
def __init__(self, var=0, msb_last=False):
|
||||||
|
@ -657,14 +229,6 @@ class Bits:
|
||||||
def __or__(self, other):
|
def __or__(self, other):
|
||||||
return Bits(int(self) | int(Bits(other)))
|
return Bits(int(self) | int(Bits(other)))
|
||||||
|
|
||||||
def __invert__(self):
|
|
||||||
# There's probably a better way to do this...
|
|
||||||
inv = str(self).replace('0', 'x').replace('1', '0').replace('x', '1')
|
|
||||||
return Bits(inv)
|
|
||||||
|
|
||||||
def __neg__(self):
|
|
||||||
return ~ self
|
|
||||||
|
|
||||||
def __radd__(self, other):
|
def __radd__(self, other):
|
||||||
return Bits(other) + self
|
return Bits(other) + self
|
||||||
|
|
||||||
|
@ -787,18 +351,27 @@ class Bits:
|
||||||
set the value of self to int(var)
|
set the value of self to int(var)
|
||||||
"""
|
"""
|
||||||
self.__value = 0
|
self.__value = 0
|
||||||
if isinstance(var, (int, bool, Bits, Bytes, Bit)):
|
if isinstance(var, Bits):
|
||||||
var_i = int(var)
|
self.__value = int(var)
|
||||||
if var_i < 0 or var_i > 255:
|
elif isinstance(var, int):
|
||||||
|
if var < 0 or var > 255:
|
||||||
raise ValueError("Integer must be between 0 and 255")
|
raise ValueError("Integer must be between 0 and 255")
|
||||||
self.__value = var_i
|
self.__value = var
|
||||||
elif isinstance(var, bytes):
|
elif isinstance(var, bytes):
|
||||||
if len(var) == 1:
|
if len(var) == 1:
|
||||||
self.__setvalue(ord(var))
|
self.__value = ord(var)
|
||||||
elif len(var) > 1:
|
elif len(var) > 1:
|
||||||
raise ValueError("bytes must be single byte with integer"
|
raise ValueError("bytes must be single byte with integer"
|
||||||
" value between 0 and 255")
|
" value between 0 and 255")
|
||||||
elif isinstance(var, (list, str)) and (len(var) <=8):
|
else:
|
||||||
|
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):
|
||||||
# handles: "01010101"
|
# handles: "01010101"
|
||||||
# ["0", "1", "0", "1", "0", "1", "0", "1"]
|
# ["0", "1", "0", "1", "0", "1", "0", "1"]
|
||||||
# [0, 1, 0, 1, 0, 1, 0, 1]
|
# [0, 1, 0, 1, 0, 1, 0, 1]
|
||||||
|
@ -809,7 +382,7 @@ class Bits:
|
||||||
self.__value += (int(bool(int(var[bit]))) *
|
self.__value += (int(bool(int(var[bit]))) *
|
||||||
(2 ** (len(var) - 1 - bit)))
|
(2 ** (len(var) - 1 - bit)))
|
||||||
else:
|
else:
|
||||||
raise TypeError("Expected compatible object")
|
raise TypeError("Expected object with len <= 8")
|
||||||
|
|
||||||
def bin(self, pad=True, reverse=False):
|
def bin(self, pad=True, reverse=False):
|
||||||
"""
|
"""
|
||||||
|
@ -817,12 +390,6 @@ class Bits:
|
||||||
pad: True to include leading zeros, False to strip leading zeroes
|
pad: True to include leading zeros, False to strip leading zeroes
|
||||||
reverse: True to return binary string representation of self as stiB.
|
reverse: True to return binary string representation of self as stiB.
|
||||||
"""
|
"""
|
||||||
if self.__value == 0:
|
|
||||||
if pad:
|
|
||||||
return "0" * 8
|
|
||||||
else:
|
|
||||||
return "0"
|
|
||||||
|
|
||||||
from math import ceil
|
from math import ceil
|
||||||
bitcount = self.__value.bit_length()
|
bitcount = self.__value.bit_length()
|
||||||
ret = ""
|
ret = ""
|
||||||
|
@ -921,21 +488,13 @@ class Bits:
|
||||||
ret.append(Bit(b))
|
ret.append(Bit(b))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def hex(self):
|
|
||||||
"""
|
|
||||||
Return the hex-string representation of self
|
|
||||||
"""
|
|
||||||
return bytes(self).hex()
|
|
||||||
|
|
||||||
|
|
||||||
class Bytes:
|
class Bytes:
|
||||||
"""
|
"""
|
||||||
A collection of Bits with convenience methods for working with binary data
|
A colletion of Bits with convenient properties for working with binary data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
def __init__(self, var=None, byteorder="big"):
|
||||||
|
|
||||||
def __init__(self, var=None, byteorder="big", bits=None):
|
|
||||||
"""
|
"""
|
||||||
var: a supported variant (object)
|
var: a supported variant (object)
|
||||||
byteorder: notimplemented, mostly ignored
|
byteorder: notimplemented, mostly ignored
|
||||||
|
@ -943,17 +502,11 @@ class Bytes:
|
||||||
self.__raw = bytearray(b'')
|
self.__raw = bytearray(b'')
|
||||||
self.__small = False
|
self.__small = False
|
||||||
self.__iter = None
|
self.__iter = None
|
||||||
self.__bit_len = 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)
|
||||||
if bits is None:
|
|
||||||
self.__bit_len = len(self.__raw)
|
|
||||||
else:
|
|
||||||
if not isinstance(bits, (int, Bytes, Bit)):
|
|
||||||
raise TypeError(f"bits argument must be int, not {type(bits)}")
|
|
||||||
self.__bit_len = int(bits)
|
|
||||||
|
|
||||||
def __bytes__(self):
|
def __bytes__(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1139,28 +692,6 @@ class Bytes:
|
||||||
chop += 1
|
chop += 1
|
||||||
return ret + bin(i)[chop:]
|
return ret + bin(i)[chop:]
|
||||||
|
|
||||||
def hex(self, sep=None, bytes_per_sep=1):
|
|
||||||
"""
|
|
||||||
Return the hex-string representation of self
|
|
||||||
"""
|
|
||||||
hexvalue = bytes(self).hex()
|
|
||||||
if sep is None or bytes_per_sep is None or bytes_per_sep == 0:
|
|
||||||
return hexvalue
|
|
||||||
else:
|
|
||||||
if bytes_per_sep > 1:
|
|
||||||
hexvalue = hexvalue[::-1] # reverse the hex string
|
|
||||||
sep = sep[::-1]
|
|
||||||
i = 0
|
|
||||||
retvalue = ""
|
|
||||||
while i < len(hexvalue):
|
|
||||||
if i > 0:
|
|
||||||
retvalue = retvalue + sep
|
|
||||||
retvalue = retvalue + hexvalue[i:(abs(bytes_per_sep * 2) + i)]
|
|
||||||
i += abs(bytes_per_sep * 2)
|
|
||||||
if bytes_per_sep > 1:
|
|
||||||
retvalue = retvalue[::-1]
|
|
||||||
return retvalue
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bytes(self):
|
def bytes(self):
|
||||||
return bytes(self)
|
return bytes(self)
|
15
dev.md
15
dev.md
|
@ -1,15 +0,0 @@
|
||||||
Steps to publish to PyPI:
|
|
||||||
|
|
||||||
1) run `make test`
|
|
||||||
2) update version in setup.py
|
|
||||||
3) Tag the current release in git to match the version in setup.py
|
|
||||||
git tag -a 1.2.0 -m 'Release 1.2.0'
|
|
||||||
4) commit any pending changes to git
|
|
||||||
git add .
|
|
||||||
git commit -m 'commit changes'
|
|
||||||
git push origin 1.2.0
|
|
||||||
5) test publish
|
|
||||||
./publish.sh test
|
|
||||||
6) publish to PyPI
|
|
||||||
./publish.sh pypi
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
# This is currently a stub. TODO: documentation
|
|
||||||
#
|
|
||||||
|
|
84
publish.sh
84
publish.sh
|
@ -1,84 +0,0 @@
|
||||||
#!/bin/sh -
|
|
||||||
|
|
||||||
_FALSE=0
|
|
||||||
_TRUE=1
|
|
||||||
__ScriptName="publish.sh"
|
|
||||||
|
|
||||||
username="__token__"
|
|
||||||
test_token=`cat test.token`
|
|
||||||
pypi_token=`cat pypi.token`
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Handle command line arguments
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
_USERNAME="__token__"
|
|
||||||
_TOKEN=""
|
|
||||||
_TESTREPO=$_FALSE
|
|
||||||
PTYPE="test"
|
|
||||||
|
|
||||||
|
|
||||||
#--- FUNCTION -----------------------------------------------------------------------------------
|
|
||||||
# NAME: __usage
|
|
||||||
# DESCRIPTION: Display usage information.
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
__usage() {
|
|
||||||
cat << EOT
|
|
||||||
Usage : ${__ScriptName} [options] <publish-type>
|
|
||||||
Options:
|
|
||||||
-h Display this help
|
|
||||||
Publish types:
|
|
||||||
- pypi Publish to pypi
|
|
||||||
- test Publish to test.pypi.org
|
|
||||||
|
|
||||||
EOT
|
|
||||||
} # ---------- end of function __usage ----------
|
|
||||||
|
|
||||||
while getopts ':h' opt
|
|
||||||
do
|
|
||||||
case "${opt}" in
|
|
||||||
h ) __usage; exit 0 ;;
|
|
||||||
\?) echo "Invalid option : $OPTARG"
|
|
||||||
__usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND-1))
|
|
||||||
|
|
||||||
|
|
||||||
# Define publish type
|
|
||||||
if [ "$#" -gt 0 ]; then
|
|
||||||
PTYPE=$1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check publish type
|
|
||||||
if [ "$(echo "$PTYPE" | grep -E '(pypi|test)')" = "" ]; then
|
|
||||||
echo "Publish type \"$PTYPE\" is invalid..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set the token
|
|
||||||
_TOKEN=$test_token # Default
|
|
||||||
_REPO="testpypi"
|
|
||||||
if [ "$(echo "$PTYPE" | grep -E '(pypi)')" = "pypi" ]; then
|
|
||||||
_TOKEN=$pypi_token
|
|
||||||
_REPO="pypi"
|
|
||||||
echo "Publishing to PYPI official..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Upgrade pip packages
|
|
||||||
python3 -m pip install pip --upgrade
|
|
||||||
python3 -m pip install setuptools --upgrade
|
|
||||||
python3 -m pip install wheel --upgrade
|
|
||||||
python3 -m pip install twine --upgrade
|
|
||||||
python3 -m pip install build --upgrade
|
|
||||||
|
|
||||||
# build current version
|
|
||||||
# note: mkae sure to update setup.py first
|
|
||||||
python3 -m build
|
|
||||||
|
|
||||||
# command: python3 -m twine upload --username $_USERNAME --password $_TOKEN --non-interactive --repository $_REPO dist/*
|
|
||||||
python3 -m twine upload --verbose --username $_USERNAME --password $_TOKEN --non-interactive --repository $_REPO dist/*
|
|
||||||
|
|
||||||
|
|
22
setup.py
22
setup.py
|
@ -4,30 +4,18 @@ with open("README.md", "r") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="binary-bits",
|
name="bits",
|
||||||
version="1.1.1",
|
version="1.0.1",
|
||||||
author="S Groesz",
|
author="S Groesz",
|
||||||
description="Provide additional methods for working with binary data",
|
description="Make your bits easier to handle",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
url="https://github.com/wolfpackmars2/bits",
|
url="https://github.com/wolfpackmars2/bits",
|
||||||
|
packages=setuptools.find_packages(),
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 5 - Production/Stable",
|
|
||||||
"Intended Audience :: Developers",
|
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"License :: OSI Approved "" MIT License",
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
python_requires='>=3.6',
|
python_requires='>=3.6',
|
||||||
py_modules=['bits'],
|
|
||||||
package_dir={'': 'src'},
|
|
||||||
test_suite='tests',
|
|
||||||
extras_require={
|
|
||||||
'test': ['coverage'],
|
|
||||||
},
|
|
||||||
project_urls={
|
|
||||||
'Source': 'http://git.groesz.org/Groesz.org/bits/',
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
'../src')))
|
'..')))
|
||||||
|
|
||||||
from bits import Bit
|
from bits import Bit
|
||||||
from bits import Bits
|
from bits import Bits
|
||||||
|
|
|
@ -64,24 +64,6 @@ class TestBit(TestCase):
|
||||||
var.toggle()
|
var.toggle()
|
||||||
self.assertTrue(var, "Bit(False).toggle() == True")
|
self.assertTrue(var, "Bit(False).toggle() == True")
|
||||||
|
|
||||||
def test_set(self):
|
|
||||||
"""Test the set() method"""
|
|
||||||
var = Bit(False)
|
|
||||||
var.set()
|
|
||||||
self.assertTrue(var, "Bit(False).set() == True")
|
|
||||||
var = Bit(True)
|
|
||||||
var.set()
|
|
||||||
self.assertTrue(var, "Bit(True).set() == True")
|
|
||||||
|
|
||||||
def test_unset(self):
|
|
||||||
"""Test the unset() method"""
|
|
||||||
var = Bit(True)
|
|
||||||
var.unset()
|
|
||||||
self.assertFalse(var, "Bit(True).unset() == False")
|
|
||||||
var = Bit(False)
|
|
||||||
var.unset()
|
|
||||||
self.assertFalse(var, "Bit(False).unset() == False")
|
|
||||||
|
|
||||||
def test_errors(self):
|
def test_errors(self):
|
||||||
"""
|
"""
|
||||||
Test that errors are raised for invalid values
|
Test that errors are raised for invalid values
|
||||||
|
|
|
@ -1,87 +1,46 @@
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from .context import Bit, Bits, Bytes
|
from .context import Bits, Bytes
|
||||||
|
|
||||||
class TestBits(TestCase):
|
class TestBits(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.testObjects = [
|
self.testObjects = [
|
||||||
{"bytes": b'\x7f',
|
{"bytes": b'\x7f',
|
||||||
"str": "01111111",
|
"bits": "01111111",
|
||||||
"int": 127,
|
"int": 127,
|
||||||
"hex": "7f",
|
|
||||||
"reverse": 254,
|
"reverse": 254,
|
||||||
"bitsObject": Bits(127),
|
"bitsObject": Bits(127)
|
||||||
"list": [Bit(0),
|
|
||||||
Bit(1),
|
|
||||||
Bit(1),
|
|
||||||
Bit(1),
|
|
||||||
Bit(1),
|
|
||||||
Bit(1),
|
|
||||||
Bit(1),
|
|
||||||
Bit(1)
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{"bytes": b'\xcf',
|
{"bytes": b'\xcf',
|
||||||
"str": "11001111",
|
"bits": "11001111",
|
||||||
"int": 207,
|
"int": 207,
|
||||||
"hex": "cf",
|
|
||||||
"reverse": 243,
|
"reverse": 243,
|
||||||
"bitsObject": Bits(207),
|
"bitsObject": Bits(207)
|
||||||
"list": [1, 1, 0, 0, 1, 1, 1, 1]
|
|
||||||
},
|
},
|
||||||
{"bytes": b'{',
|
{"bytes": b'{',
|
||||||
"str": "01111011",
|
"bits": "01111011",
|
||||||
"int": 123,
|
"int": 123,
|
||||||
"hex": "7b",
|
|
||||||
"reverse": 222,
|
"reverse": 222,
|
||||||
"bitsObject": Bits(123),
|
"bitsObject": Bits(123)
|
||||||
"list": ["0", "1", "1", "1", "1", "0", "1", "1"]
|
|
||||||
|
|
||||||
},
|
},
|
||||||
{"bytes": b'<',
|
{"bytes": b'<',
|
||||||
"str": "00111100",
|
"bits": "00111100",
|
||||||
"int": 60,
|
"int": 60,
|
||||||
"hex": "3c",
|
|
||||||
"reverse": 60,
|
"reverse": 60,
|
||||||
"bitsObject": Bits(60),
|
"bitsObject": Bits(60)
|
||||||
"list": [False,
|
|
||||||
False,
|
|
||||||
True,
|
|
||||||
True,
|
|
||||||
True,
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
False
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{"bytes": b'>',
|
{"bytes": b'>',
|
||||||
"str": "00111110",
|
"bits": "00111110",
|
||||||
"int": 62,
|
"int": 62,
|
||||||
"hex": "3e",
|
|
||||||
"reverse": 124,
|
"reverse": 124,
|
||||||
"bitsObject": Bits(62),
|
"bitsObject": Bits(62)
|
||||||
"list": [0,
|
|
||||||
False,
|
|
||||||
"1",
|
|
||||||
1,
|
|
||||||
Bit("1"),
|
|
||||||
Bit(True),
|
|
||||||
Bit(1),
|
|
||||||
Bit(False)
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{"bytes": b'=',
|
|
||||||
"str": "00111101",
|
|
||||||
"int": 61,
|
|
||||||
"hex": "3d",
|
|
||||||
"reverse": 188,
|
|
||||||
"bitsObject": Bits(61),
|
|
||||||
"list": [True, 1, 1, True, Bit(0), Bit(1)]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
def test_class(self):
|
def test_class(self):
|
||||||
"""Test various class features"""
|
"""
|
||||||
|
Test various class features
|
||||||
|
"""
|
||||||
with self.subTest("Reject values > 255"):
|
with self.subTest("Reject values > 255"):
|
||||||
self.assertRaises(ValueError, Bits, 256)
|
self.assertRaises(ValueError, Bits, 256)
|
||||||
with self.subTest("Reject values < 0"):
|
with self.subTest("Reject values < 0"):
|
||||||
|
@ -95,59 +54,58 @@ class TestBits(TestCase):
|
||||||
self.assertEqual(len(Bits(0)), 8)
|
self.assertEqual(len(Bits(0)), 8)
|
||||||
|
|
||||||
def test_bytes(self):
|
def test_bytes(self):
|
||||||
"""Test conversion to bytes objects"""
|
"""
|
||||||
|
Test conversion to bytes object
|
||||||
|
"""
|
||||||
for testcase in self.testObjects:
|
for testcase in self.testObjects:
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
||||||
self.assertEqual(bytes(testcase["bitsObject"]),
|
self.assertEqual(bytes(testcase["bitsObject"]),
|
||||||
testcase["bytes"])
|
testcase["bytes"])
|
||||||
|
|
||||||
def test_int(self):
|
def test_int(self):
|
||||||
"""Test integer conversion"""
|
"""
|
||||||
|
Test integer conversion
|
||||||
|
"""
|
||||||
for testcase in self.testObjects:
|
for testcase in self.testObjects:
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
||||||
self.assertEqual(int(testcase["bitsObject"]), testcase["int"])
|
self.assertEqual(int(testcase["bitsObject"]), testcase["int"])
|
||||||
|
|
||||||
def test_hex(self):
|
|
||||||
"""Test conversion to hex"""
|
|
||||||
for testcase in self.testObjects:
|
|
||||||
with self.subTest("testcase[\"hex\"]: " + str(testcase["hex"])):
|
|
||||||
self.assertEqual(testcase["bitsObject"].hex(), testcase["hex"])
|
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
"""Test string representation"""
|
"""
|
||||||
|
Test string representation
|
||||||
|
"""
|
||||||
for testcase in self.testObjects:
|
for testcase in self.testObjects:
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
||||||
s = str(testcase["bitsObject"])
|
s = str(testcase["bitsObject"])
|
||||||
self.assertEqual(s, testcase["str"])
|
self.assertEqual(s, testcase["bits"])
|
||||||
|
|
||||||
def test_list(self):
|
|
||||||
"""Test list conversion"""
|
|
||||||
for testcase in self.testObjects:
|
|
||||||
with self.subTest("testcase[\"list\"]: " + str(testcase["list"])):
|
|
||||||
self.assertEqual(testcase["bytes"],
|
|
||||||
bytes(Bits(testcase["list"])))
|
|
||||||
|
|
||||||
def test_bits(self):
|
def test_bits(self):
|
||||||
"""Test bit representation"""
|
"""
|
||||||
|
Test bit representation
|
||||||
|
"""
|
||||||
for testcase in self.testObjects:
|
for testcase in self.testObjects:
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
||||||
self.assertEqual(testcase["bitsObject"].bin(),
|
self.assertEqual(testcase["bitsObject"].bin(),
|
||||||
testcase["str"])
|
testcase["bits"])
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \
|
||||||
+ " [without leading zeros]"):
|
+ " [without leading zeros]"):
|
||||||
self.assertEqual(testcase["bitsObject"].bin(pad=False),
|
self.assertEqual(testcase["bitsObject"].bin(pad=False),
|
||||||
testcase["str"].lstrip("0"))
|
testcase["bits"].lstrip("0"))
|
||||||
|
|
||||||
def test_reverse(self):
|
def test_reverse(self):
|
||||||
"""Test the reverse function changes the object bitorder and value"""
|
"""
|
||||||
|
Test the reverse function changes the object bitorder and value
|
||||||
|
"""
|
||||||
for testcase in self.testObjects:
|
for testcase in self.testObjects:
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"])):
|
||||||
testcase["bitsObject"].reverse()
|
testcase["bitsObject"].reverse()
|
||||||
self.assertEqual(testcase["bitsObject"].bin(),
|
self.assertEqual(testcase["bitsObject"].bin(),
|
||||||
testcase["str"][::-1])
|
testcase["bits"][::-1])
|
||||||
|
|
||||||
def test_membership_operators(self):
|
def test_membership_operators(self):
|
||||||
"""Test the membership operator (x in y)"""
|
"""
|
||||||
|
Test the membership operator (x in y)
|
||||||
|
"""
|
||||||
with self.subTest("should all be True"):
|
with self.subTest("should all be True"):
|
||||||
for i in range(1, 256):
|
for i in range(1, 256):
|
||||||
self.assertTrue(i in Bits(255), f"Bits({i}) in Bits(255) fail")
|
self.assertTrue(i in Bits(255), f"Bits({i}) in Bits(255) fail")
|
||||||
|
@ -187,7 +145,9 @@ class TestBits(TestCase):
|
||||||
"Bits(80) and Bits(64) == Bits(64)")
|
"Bits(80) and Bits(64) == Bits(64)")
|
||||||
|
|
||||||
def test_comparisons(self):
|
def test_comparisons(self):
|
||||||
"""Test the comparison operators"""
|
"""
|
||||||
|
Test the comparison operators
|
||||||
|
"""
|
||||||
for testcase in self.testObjects:
|
for testcase in self.testObjects:
|
||||||
with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \
|
with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \
|
||||||
+ " [==]"):
|
+ " [==]"):
|
||||||
|
|
|
@ -19,8 +19,6 @@ class TestBytes(TestCase):
|
||||||
test_list_of_ints = []
|
test_list_of_ints = []
|
||||||
test_list_of_str = []
|
test_list_of_str = []
|
||||||
for i in range(0, 100):
|
for i in range(0, 100):
|
||||||
# Generate 100 random test cases, each with max_value between
|
|
||||||
# 9 and 9,999,999,999,999,999,999,999,999 (25 9's)
|
|
||||||
max_value = int("9" * randint(1, 25))
|
max_value = int("9" * randint(1, 25))
|
||||||
test_value = randint(1, max_value)
|
test_value = randint(1, max_value)
|
||||||
bitesize = ceil(test_value.bit_length() / 8)
|
bitesize = ceil(test_value.bit_length() / 8)
|
||||||
|
@ -76,8 +74,7 @@ class TestBytes(TestCase):
|
||||||
# print(f"\t\t{testcase}")
|
# print(f"\t\t{testcase}")
|
||||||
try:
|
try:
|
||||||
self.assertIsInstance(eval(test), eval(compare),
|
self.assertIsInstance(eval(test), eval(compare),
|
||||||
"{test} is instance of {compare}"
|
f"{test} is instance of {compare}")
|
||||||
)
|
|
||||||
except:
|
except:
|
||||||
import pdb
|
import pdb
|
||||||
pdb.set_trace()
|
pdb.set_trace()
|
||||||
|
@ -94,43 +91,6 @@ class TestBytes(TestCase):
|
||||||
with self.assertRaises(TypeError, msg="Bytes(\"1234\")"):
|
with self.assertRaises(TypeError, msg="Bytes(\"1234\")"):
|
||||||
Bytes("1234")
|
Bytes("1234")
|
||||||
|
|
||||||
def test_hex(self):
|
|
||||||
"""
|
|
||||||
Test conversion to hex string
|
|
||||||
"""
|
|
||||||
with self.subTest("Test Bytes.hex() using random values"):
|
|
||||||
for testcase in self.testcases["bytes"]:
|
|
||||||
self.assertEqual(Bytes(testcase).hex(), testcase.hex(),
|
|
||||||
f"Bytes({testcase}).hex() == {testcase}.hex()"
|
|
||||||
)
|
|
||||||
with self.subTest("Test hex() function with known values"):
|
|
||||||
self.assertEqual(Bytes(1234).hex(), "04d2",
|
|
||||||
f"Bytes(1234).hex() == '04d2'")
|
|
||||||
self.assertEqual(Bytes(1234).hex(":"), "04:d2",
|
|
||||||
f"Bytes(1234).hex(':') == '04:d2'")
|
|
||||||
self.assertEqual(Bytes(1234).hex(":", 1), "04:d2",
|
|
||||||
f"Bytes(1234).hex(':', 1) == '04:d2'")
|
|
||||||
with self.subTest("Advanced hex() test"):
|
|
||||||
testcase = b'UUDDLRLRAB'
|
|
||||||
self.assertEqual(Bytes(testcase).hex(), testcase.hex(),
|
|
||||||
f"Bytes({testcase}).hex() == {testcase}.hex()")
|
|
||||||
tests = [['55:55:44:44:4c:52:4c:52:41:42', ":", 1],
|
|
||||||
['55:55:44:44:4c:52:4c:52:41:42', ":", -1],
|
|
||||||
['5555:44444c52:4c524142', ":", 4],
|
|
||||||
['55554444:4c524c52:4142', ":", -4],
|
|
||||||
['55 - 55 - 44 - 44 - 4c - 52 - 4c - 52 - 41 - 42', " - ",
|
|
||||||
1],
|
|
||||||
['55, 55, 44, 44, 4c, 52, 4c, 52, 41, 42', ", ", 1],
|
|
||||||
['5555, 44444c52, 4c524142', ", ", 4],
|
|
||||||
['55554444, 4c524c52, 4142', ", ", -4]
|
|
||||||
]
|
|
||||||
for subt in tests:
|
|
||||||
self.assertEqual(Bytes(testcase).hex(sep=subt[1],
|
|
||||||
bytes_per_sep=subt[2]),
|
|
||||||
subt[0],
|
|
||||||
f"Bytes({testcase}).hex(sep='{subt[1]}', " +
|
|
||||||
f"bytes_per_sep={subt[2]}) == {subt[0]}")
|
|
||||||
|
|
||||||
def test_comparison_operators(self):
|
def test_comparison_operators(self):
|
||||||
"""
|
"""
|
||||||
Test the comparison operators with Bytes objects
|
Test the comparison operators with Bytes objects
|
||||||
|
|
Loading…
Reference in New Issue