easybits 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- easybits/__init__.py +111 -0
- easybits/errors.py +15 -0
- easybits/util.py +5 -0
- easybits-0.1.0.dist-info/METADATA +18 -0
- easybits-0.1.0.dist-info/RECORD +6 -0
- easybits-0.1.0.dist-info/WHEEL +4 -0
easybits/__init__.py
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
from bitarray import bitarray
|
2
|
+
from bitarray.util import (
|
3
|
+
zeros,
|
4
|
+
ones,
|
5
|
+
int2ba,
|
6
|
+
ba2int,
|
7
|
+
)
|
8
|
+
from easybits.util import is_bit_string
|
9
|
+
from easybits.errors import (
|
10
|
+
NotEnoughBits,
|
11
|
+
IntegersRequireLength,
|
12
|
+
IntegerAdditionRequiresSameLength,
|
13
|
+
)
|
14
|
+
|
15
|
+
class Bits(bitarray):
|
16
|
+
"""A wrapper around bitarray with a more idiomatic interface for beginners.
|
17
|
+
- Integers are always signed.
|
18
|
+
"""
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def zeros(cls, length):
|
22
|
+
return Bits(zeros(length))
|
23
|
+
|
24
|
+
@classmethod
|
25
|
+
def ones(cls, length):
|
26
|
+
return Bits(ones(length))
|
27
|
+
|
28
|
+
def __new__(cls, value, length=None, encoding='ascii'):
|
29
|
+
if isinstance(value, bytes):
|
30
|
+
bits = bitarray()
|
31
|
+
bits.frombytes(value)
|
32
|
+
elif isinstance(value, bool):
|
33
|
+
bits = bitarray([value])
|
34
|
+
elif isinstance(value, int):
|
35
|
+
if not length:
|
36
|
+
raise IntegersRequireLength()
|
37
|
+
bits = int2ba(value, length=length, signed=True)
|
38
|
+
elif isinstance(value, str):
|
39
|
+
if is_bit_string(value):
|
40
|
+
bits = bitarray(value)
|
41
|
+
else:
|
42
|
+
bits = bitarray()
|
43
|
+
bits.frombytes(value.encode(encoding))
|
44
|
+
elif isinstance(value, list):
|
45
|
+
bits = bitarray(value)
|
46
|
+
elif isinstance(value, bitarray):
|
47
|
+
bits = value
|
48
|
+
else:
|
49
|
+
raise ValueError(f"Can't create bits from {value}")
|
50
|
+
if length:
|
51
|
+
if length < len(bits):
|
52
|
+
raise NotEnoughBits(value, length)
|
53
|
+
else:
|
54
|
+
sized_bits = bitarray(length)
|
55
|
+
sized_bits[-len(bits):] = bits
|
56
|
+
else:
|
57
|
+
sized_bits = bits
|
58
|
+
return super().__new__(cls, sized_bits)
|
59
|
+
|
60
|
+
def __str__(self):
|
61
|
+
bits = self.to01()
|
62
|
+
|
63
|
+
def __repr__(self):
|
64
|
+
return self.to01()
|
65
|
+
|
66
|
+
@property
|
67
|
+
def bool(self):
|
68
|
+
return [bool(b) for b in self.tolist()]
|
69
|
+
|
70
|
+
@property
|
71
|
+
def int(self):
|
72
|
+
return ba2int(self, signed=True)
|
73
|
+
|
74
|
+
@property
|
75
|
+
def bytes(self):
|
76
|
+
return self.tobytes()
|
77
|
+
|
78
|
+
@property
|
79
|
+
def ascii(self):
|
80
|
+
return self.bytes.decode("ascii")
|
81
|
+
|
82
|
+
def __add__(self, other):
|
83
|
+
"""Performs bitwise addition on `self` and `other`. Does not
|
84
|
+
check for overflow.
|
85
|
+
"""
|
86
|
+
a, b = self, Bits(other)
|
87
|
+
if not len(a) == len(b):
|
88
|
+
raise IntegerAdditionRequiresSameLength()
|
89
|
+
result = Bits.zeros(len(a))
|
90
|
+
carry = 0
|
91
|
+
for i in reversed(range(len(a))):
|
92
|
+
result[i] = a[i] ^ b[i] ^ carry
|
93
|
+
carry = (a[i] & b[i]) | (a[i] & carry) | (b[i] & carry)
|
94
|
+
return result
|
95
|
+
|
96
|
+
def __sub__(self, other):
|
97
|
+
"""Performs bitwise addition on `self` and `other`. Does not
|
98
|
+
check for overflow.
|
99
|
+
"""
|
100
|
+
a, b = self, Bits(other)
|
101
|
+
if not len(a) == len(b):
|
102
|
+
raise IntegerAdditionRequiresSameLength()
|
103
|
+
return a + (-b)
|
104
|
+
|
105
|
+
def __neg__(self):
|
106
|
+
"""Treats `self` as an integer, and flips its sign.
|
107
|
+
"""
|
108
|
+
if self[0]:
|
109
|
+
return ~self + Bits(1, length=len(self))
|
110
|
+
else:
|
111
|
+
return ~(self + Bits(-1, length=len(self)))
|
easybits/errors.py
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class BitsError(Exception):
|
2
|
+
message = "Bits error"
|
3
|
+
|
4
|
+
def __str__(self):
|
5
|
+
return self.message
|
6
|
+
|
7
|
+
class NotEnoughBits(BitsError):
|
8
|
+
def __init__(self, obj, length):
|
9
|
+
self.message = f"{obj} cannot fit into {length} bits."
|
10
|
+
|
11
|
+
class IntegersRequireLength(BitsError):
|
12
|
+
message = "Binary representations of integers require that a length be provided."
|
13
|
+
|
14
|
+
class IntegerAdditionRequiresSameLength(BitsError):
|
15
|
+
message = "Can only add integers of the same length."
|
easybits/util.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: easybits
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A friendly interface for exploring bits.
|
5
|
+
Author: Chris Proctor
|
6
|
+
Author-email: chris@chrisproctor.net
|
7
|
+
Requires-Python: >=3.9,<4.0
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Requires-Dist: bitarray (>=3.0.0,<4.0.0)
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
|
15
|
+
# Easybits
|
16
|
+
|
17
|
+
A friendly interface for exploring bits.
|
18
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
easybits/__init__.py,sha256=qnmlE5N3MkBB6_pQavtgAK6uzV0dj0zi50puMmUwRGQ,3144
|
2
|
+
easybits/errors.py,sha256=MPQGCYUave-PCKP4IkfIS2NJzL2j2KH2W3rlPofsigo,478
|
3
|
+
easybits/util.py,sha256=GYlFDgqk1sBkFidKsoo9xaO7QZ8_v7KFavP2KnV0mZ8,100
|
4
|
+
easybits-0.1.0.dist-info/METADATA,sha256=XnRyaeO0SiTqzWd6Q2GX0B7DWciDl38iylJbQgP_5Sc,525
|
5
|
+
easybits-0.1.0.dist-info/WHEEL,sha256=kLuE8m1WYU0Ig0_YEGrXyTtiJvKPpLpDEiChiNyei5Y,88
|
6
|
+
easybits-0.1.0.dist-info/RECORD,,
|